Added
Link Here
|
1 |
/* |
2 |
* Copyright (c) 2017 Jan Kokemüller |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions |
6 |
* are met: |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* |
13 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
14 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
16 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
17 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
18 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
19 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
20 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
21 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
22 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
23 |
* SUCH DAMAGE. |
24 |
*/ |
25 |
|
26 |
#include <sys/cdefs.h> |
27 |
__FBSDID("$FreeBSD$"); |
28 |
|
29 |
#include <sys/param.h> |
30 |
#include <sys/capsicum.h> |
31 |
#include <sys/socket.h> |
32 |
#include <sys/sysctl.h> |
33 |
#include <sys/stat.h> |
34 |
|
35 |
#include <netinet/in.h> |
36 |
#include <arpa/inet.h> |
37 |
|
38 |
#include <atf-c.h> |
39 |
#include <dlfcn.h> |
40 |
#include <errno.h> |
41 |
#include <stdarg.h> |
42 |
#include <stdlib.h> |
43 |
#include <string.h> |
44 |
|
45 |
#include "freebsd_test_suite/macros.h" |
46 |
|
47 |
static int rootfd = -1; |
48 |
|
49 |
/* circumvent bug 215690 */ |
50 |
int |
51 |
open(const char *path, int flags, ...) |
52 |
{ |
53 |
mode_t mode = 0; |
54 |
|
55 |
if (flags & O_CREAT) { |
56 |
va_list ap; |
57 |
va_start(ap, flags); |
58 |
mode = (mode_t) va_arg(ap, int); |
59 |
va_end(ap); |
60 |
} |
61 |
|
62 |
if (path && path[0] == '/' && rootfd >= 0) { |
63 |
return (openat(rootfd, path + 1, flags, mode)); |
64 |
} else { |
65 |
return (openat(AT_FDCWD, path, flags, mode)); |
66 |
} |
67 |
} |
68 |
|
69 |
static void |
70 |
check_capsicum(void) |
71 |
{ |
72 |
ATF_REQUIRE_FEATURE("security_capabilities"); |
73 |
ATF_REQUIRE_FEATURE("security_capability_mode"); |
74 |
|
75 |
ATF_REQUIRE((rootfd = open("/", O_EXEC | O_CLOEXEC)) >= 0); |
76 |
} |
77 |
|
78 |
typedef int (*socket_fun)(int, const struct sockaddr *, socklen_t); |
79 |
|
80 |
static int |
81 |
connectat_fdcwd(int s, const struct sockaddr *name, socklen_t namelen) |
82 |
{ |
83 |
|
84 |
return (connectat(AT_FDCWD, s, name, namelen)); |
85 |
} |
86 |
|
87 |
static int |
88 |
bindat_fdcwd(int s, const struct sockaddr *name, socklen_t namelen) |
89 |
{ |
90 |
|
91 |
return (bindat(AT_FDCWD, s, name, namelen)); |
92 |
} |
93 |
|
94 |
|
95 |
ATF_TC(bindat_connectat_1); |
96 |
ATF_TC_HEAD(bindat_connectat_1, tc) |
97 |
{ |
98 |
atf_tc_set_md_var(tc, "descr", |
99 |
"Verify that connect/bind work in normal case"); |
100 |
} |
101 |
|
102 |
static void |
103 |
check_1(socket_fun f, int s, const struct sockaddr_in *name) |
104 |
{ |
105 |
|
106 |
ATF_REQUIRE((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0); |
107 |
ATF_REQUIRE_ERRNO(EAFNOSUPPORT, |
108 |
f(s, (const struct sockaddr *)(name), |
109 |
sizeof(struct sockaddr_in)) < 0); |
110 |
} |
111 |
|
112 |
ATF_TC_BODY(bindat_connectat_1, tc) |
113 |
{ |
114 |
struct sockaddr_in sin; |
115 |
|
116 |
memset(&sin, 0, sizeof(sin)); |
117 |
sin.sin_family = AF_INET; |
118 |
sin.sin_port = htons(0); |
119 |
sin.sin_addr.s_addr = htonl(0xE0000000); |
120 |
|
121 |
check_1(bindat_fdcwd, 0, &sin); |
122 |
check_1(bind, 0, &sin); |
123 |
check_1(connectat_fdcwd, 0, &sin); |
124 |
check_1(connect, 0, &sin); |
125 |
} |
126 |
|
127 |
|
128 |
ATF_TC(bindat_connectat_2); |
129 |
ATF_TC_HEAD(bindat_connectat_2, tc) |
130 |
{ |
131 |
atf_tc_set_md_var(tc, "descr", |
132 |
"Verify that connect/bind are disabled in cap-mode"); |
133 |
} |
134 |
|
135 |
static void |
136 |
check_2(socket_fun f, int s, const struct sockaddr_in *name) |
137 |
{ |
138 |
|
139 |
ATF_REQUIRE_ERRNO(ECAPMODE, |
140 |
f(s, (const struct sockaddr *)name, |
141 |
sizeof(struct sockaddr_in)) < 0); |
142 |
} |
143 |
|
144 |
ATF_TC_BODY(bindat_connectat_2, tc) |
145 |
{ |
146 |
int sock; |
147 |
struct sockaddr_in sin; |
148 |
|
149 |
check_capsicum(); |
150 |
|
151 |
ATF_REQUIRE(cap_enter() >= 0); |
152 |
|
153 |
/* note: sock is created _after_ cap_enter() and contains all rights */ |
154 |
ATF_REQUIRE((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0); |
155 |
|
156 |
memset(&sin, 0, sizeof(sin)); |
157 |
sin.sin_family = AF_INET; |
158 |
/* dummy port and multicast address (224.0.0.0) to distinguish two |
159 |
* cases: |
160 |
* - ECAPMODE/ENOTCAPABLE --> call blocked by capsicum |
161 |
* - EAFNOSUPPORT --> call went through to protocol layer |
162 |
*/ |
163 |
sin.sin_port = htons(0); |
164 |
sin.sin_addr.s_addr = htonl(0xE0000000); |
165 |
|
166 |
check_2(bindat_fdcwd, sock, &sin); |
167 |
check_2(bind, sock, &sin); |
168 |
check_2(connectat_fdcwd, sock, &sin); |
169 |
check_2(connect, sock, &sin); |
170 |
} |
171 |
|
172 |
|
173 |
ATF_TC(bindat_connectat_3); |
174 |
ATF_TC_HEAD(bindat_connectat_3, tc) |
175 |
{ |
176 |
atf_tc_set_md_var(tc, "descr", |
177 |
"Check that taking away CAP_BIND/CAP_CONNECT " |
178 |
"sabotages bind/connect"); |
179 |
} |
180 |
|
181 |
static void |
182 |
check_3(socket_fun f, int s, const struct sockaddr_in *name, |
183 |
cap_rights_t *rights, cap_rights_t *sub_rights) |
184 |
{ |
185 |
|
186 |
ATF_REQUIRE((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0); |
187 |
ATF_REQUIRE(cap_rights_limit(s, rights) >= 0); |
188 |
ATF_REQUIRE_ERRNO(EAFNOSUPPORT, |
189 |
f(s, (const struct sockaddr *)name, |
190 |
sizeof(struct sockaddr_in)) < 0); |
191 |
ATF_REQUIRE(cap_rights_limit(s, |
192 |
cap_rights_remove(rights, sub_rights)) >= 0); |
193 |
ATF_REQUIRE_ERRNO(ENOTCAPABLE, |
194 |
f(s, (const struct sockaddr *)name, |
195 |
sizeof(struct sockaddr_in)) < 0); |
196 |
} |
197 |
|
198 |
ATF_TC_BODY(bindat_connectat_3, tc) |
199 |
{ |
200 |
struct sockaddr_in sin; |
201 |
cap_rights_t rights, sub_rights; |
202 |
|
203 |
check_capsicum(); |
204 |
|
205 |
memset(&sin, 0, sizeof(sin)); |
206 |
sin.sin_family = AF_INET; |
207 |
sin.sin_port = htons(0); |
208 |
sin.sin_addr.s_addr = htonl(0xE0000000); |
209 |
|
210 |
check_3(bindat_fdcwd, 0, &sin, |
211 |
cap_rights_init(&rights, CAP_SOCK_SERVER), |
212 |
cap_rights_init(&sub_rights, CAP_BIND)); |
213 |
check_3(bind, 0, &sin, |
214 |
cap_rights_init(&rights, CAP_SOCK_SERVER), |
215 |
cap_rights_init(&sub_rights, CAP_BIND)); |
216 |
check_3(connectat_fdcwd, 0, &sin, |
217 |
cap_rights_init(&rights, CAP_SOCK_CLIENT), |
218 |
cap_rights_init(&sub_rights, CAP_CONNECT)); |
219 |
check_3(connect, 0, &sin, |
220 |
cap_rights_init(&rights, CAP_SOCK_CLIENT), |
221 |
cap_rights_init(&sub_rights, CAP_CONNECT)); |
222 |
} |
223 |
|
224 |
|
225 |
ATF_TP_ADD_TCS(tp) |
226 |
{ |
227 |
|
228 |
ATF_TP_ADD_TC(tp, bindat_connectat_1); |
229 |
ATF_TP_ADD_TC(tp, bindat_connectat_2); |
230 |
ATF_TP_ADD_TC(tp, bindat_connectat_3); |
231 |
|
232 |
return (atf_no_error()); |
233 |
} |