Deleted Added
full compact
cap_test_capmode.c (221431) cap_test_capmode.c (224651)
1/*-
2 * Copyright (c) 2008-2009 Robert N. M. Watson
1/*-
2 * Copyright (c) 2008-2009 Robert N. M. Watson
3 * Copyright (c) 2011 Jonathan Anderson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright

--- 7 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright

--- 7 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
26 * $FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 221431 2011-05-04 12:44:46Z jonathan $
27 * $FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 224651 2011-08-04 14:20:13Z jonathan $
27 */
28
29/*
30 * Test routines to make sure a variety of system calls are or are not
31 * available in capability mode. The goal is not to see if they work, just
32 * whether or not they return the expected ECAPMODE.
33 */
34
35#include <sys/cdefs.h>
28 */
29
30/*
31 * Test routines to make sure a variety of system calls are or are not
32 * available in capability mode. The goal is not to see if they work, just
33 * whether or not they return the expected ECAPMODE.
34 */
35
36#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 221431 2011-05-04 12:44:46Z jonathan $");
37__FBSDID("$FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 224651 2011-08-04 14:20:13Z jonathan $");
37
38#include <sys/param.h>
39#include <sys/capability.h>
38
39#include <sys/param.h>
40#include <sys/capability.h>
41#include <sys/errno.h>
40#include <sys/mman.h>
41#include <sys/mount.h>
42#include <sys/mman.h>
43#include <sys/mount.h>
42#include <sys/poll.h>
43#include <sys/socket.h>
44#include <sys/stat.h>
45#include <sys/wait.h>
46
47#include <machine/sysarch.h>
44#include <sys/socket.h>
45#include <sys/stat.h>
46#include <sys/wait.h>
47
48#include <machine/sysarch.h>
48#include <netinet/in.h>
49
50#include <err.h>
49
50#include <err.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
51#include <fcntl.h>
52#include <stdlib.h>
53#include <string.h>
54#include <unistd.h>
55
57/* Need to check machine-dependent sysarch(). */
58#define ARCH_IS(s) (!strncmp(s, MACHINE, sizeof(s) + 1))
59
60#include "cap_test.h"
61
56#include "cap_test.h"
57
62void
58#define CHECK_SYSCALL_VOID_NOT_ECAPMODE(syscall, ...) do { \
59 errno = 0; \
60 (void)syscall(__VA_ARGS__); \
61 if (errno == ECAPMODE) \
62 FAIL("capmode: %s failed with ECAPMODE", #syscall); \
63} while (0)
64
65int
63test_capmode(void)
64{
66test_capmode(void)
67{
65 struct sockaddr_in sin;
66 struct statfs statfs;
67 struct stat sb;
68 struct statfs statfs;
69 struct stat sb;
68 ssize_t len;
69 long sysarch_arg = 0;
70 long sysarch_arg = 0;
70 int fd, fd_close, fd_dir, fd_file, fd_socket, fd2[2], ret;
71 int fd_close, fd_dir, fd_file, fd_socket, fd2[2];
72 int success = PASSED;
71 pid_t pid, wpid;
72 char ch;
73
73 pid_t pid, wpid;
74 char ch;
75
74 fd_file = open("/tmp/cap_test_syscalls", O_RDWR|O_CREAT, 0644);
75 if (fd_file < 0)
76 err(-1, "test_syscalls:prep: open cap_test_syscalls");
76 /* Open some files to play with. */
77 REQUIRE(fd_file = open("/tmp/cap_capmode", O_RDWR|O_CREAT, 0644));
78 REQUIRE(fd_close = open("/dev/null", O_RDWR));
79 REQUIRE(fd_dir = open("/tmp", O_RDONLY));
80 REQUIRE(fd_socket = socket(PF_INET, SOCK_DGRAM, 0));
77
81
78 fd_close = open("/dev/null", O_RDWR);
79 if (fd_close < 0)
80 err(-1, "test_syscalls:prep: open /dev/null");
82 /* Enter capability mode. */
83 REQUIRE(cap_enter());
81
84
82 fd_dir = open("/tmp", O_RDONLY);
83 if (fd_dir < 0)
84 err(-1, "test_syscalls:prep: open /tmp");
85 /*
86 * System calls that are not permitted in capability mode.
87 */
88 CHECK_CAPMODE(access, "/tmp/cap_capmode_access", F_OK);
89 CHECK_CAPMODE(acct, "/tmp/cap_capmode_acct");
90 CHECK_CAPMODE(bind, PF_INET, NULL, 0);
91 CHECK_CAPMODE(chdir, "/tmp/cap_capmode_chdir");
92 CHECK_CAPMODE(chflags, "/tmp/cap_capmode_chflags", UF_NODUMP);
93 CHECK_CAPMODE(chmod, "/tmp/cap_capmode_chmod", 0644);
94 CHECK_CAPMODE(chown, "/tmp/cap_capmode_chown", -1, -1);
95 CHECK_CAPMODE(chroot, "/tmp/cap_capmode_chroot");
96 CHECK_CAPMODE(connect, PF_INET, NULL, 0);
97 CHECK_CAPMODE(creat, "/tmp/cap_capmode_creat", 0644);
98 CHECK_CAPMODE(fchdir, fd_dir);
99 CHECK_CAPMODE(getfsstat, &statfs, sizeof(statfs), MNT_NOWAIT);
100 CHECK_CAPMODE(link, "/tmp/foo", "/tmp/bar");
101 CHECK_CAPMODE(lstat, "/tmp/cap_capmode_lstat", &sb);
102 CHECK_CAPMODE(mknod, "/tmp/capmode_mknod", 06440, 0);
103 CHECK_CAPMODE(mount, "procfs", "/not_mounted", 0, NULL);
104 CHECK_CAPMODE(open, "/dev/null", O_RDWR);
105 CHECK_CAPMODE(readlink, "/tmp/cap_capmode_readlink", NULL, 0);
106 CHECK_CAPMODE(revoke, "/tmp/cap_capmode_revoke");
107 CHECK_CAPMODE(stat, "/tmp/cap_capmode_stat", &sb);
108 CHECK_CAPMODE(symlink,
109 "/tmp/cap_capmode_symlink_from",
110 "/tmp/cap_capmode_symlink_to");
111 CHECK_CAPMODE(unlink, "/tmp/cap_capmode_unlink");
112 CHECK_CAPMODE(unmount, "/not_mounted", 0);
85
113
86 fd_socket = socket(PF_INET, SOCK_DGRAM, 0);
87 if (fd_socket < 0)
88 err(-1, "test_syscalls:prep: socket");
114 /*
115 * System calls that are permitted in capability mode.
116 */
117 CHECK_SYSCALL_SUCCEEDS(close, fd_close);
118 CHECK_SYSCALL_SUCCEEDS(dup, fd_file);
119 CHECK_SYSCALL_SUCCEEDS(fstat, fd_file, &sb);
120 CHECK_SYSCALL_SUCCEEDS(lseek, fd_file, SEEK_SET, 0);
121 CHECK_SYSCALL_SUCCEEDS(msync, &fd_file, 8192, MS_ASYNC);
122 CHECK_SYSCALL_SUCCEEDS(profil, NULL, 0, 0, 0);
123 CHECK_SYSCALL_SUCCEEDS(read, fd_file, &ch, sizeof(ch));
124 CHECK_SYSCALL_SUCCEEDS(recvfrom, fd_socket, NULL, 0, 0, NULL, NULL);
125 CHECK_SYSCALL_SUCCEEDS(setuid, getuid());
126 CHECK_SYSCALL_SUCCEEDS(write, fd_file, &ch, sizeof(ch));
89
127
90 if (cap_enter() < 0)
91 err(-1, "test_syscalls:prep: cap_enter");
128 /*
129 * These calls will fail for lack of e.g. a proper name to send to,
130 * but they are allowed in capability mode, so errno != ECAPMODE.
131 */
132 CHECK_NOT_CAPMODE(accept, fd_socket, NULL, NULL);
133 CHECK_NOT_CAPMODE(getpeername, fd_socket, NULL, NULL);
134 CHECK_NOT_CAPMODE(getsockname, fd_socket, NULL, NULL);
135 CHECK_NOT_CAPMODE(fchflags, fd_file, UF_NODUMP);
136 CHECK_NOT_CAPMODE(recvmsg, fd_socket, NULL, 0);
137 CHECK_NOT_CAPMODE(sendmsg, fd_socket, NULL, 0);
138 CHECK_NOT_CAPMODE(sendto, fd_socket, NULL, 0, 0, NULL, 0);
92
139
93
94 bzero(&sin, sizeof(sin));
95 sin.sin_len = sizeof(sin);
96 sin.sin_family = AF_INET;
97
98 /*
140 /*
99 * Here begin the tests, sorted roughly alphabetically by system call
100 * name.
141 * System calls which should be allowed in capability mode, but which
142 * don't return errors, and are thus difficult to check.
143 *
144 * We will try anyway, by checking errno.
101 */
145 */
102 fd = accept(fd_socket, NULL, NULL);
103 if (fd < 0) {
104 if (errno == ECAPMODE)
105 warnx("test_syscalls:accept");
106 } else {
107 warnx("test_syscalls:accept succeeded");
108 close(fd);
109 }
146 CHECK_SYSCALL_VOID_NOT_ECAPMODE(getegid);
147 CHECK_SYSCALL_VOID_NOT_ECAPMODE(geteuid);
148 CHECK_SYSCALL_VOID_NOT_ECAPMODE(getgid);
149 CHECK_SYSCALL_VOID_NOT_ECAPMODE(getpid);
150 CHECK_SYSCALL_VOID_NOT_ECAPMODE(getppid);
151 CHECK_SYSCALL_VOID_NOT_ECAPMODE(getuid);
110
152
111 if (access("/tmp/cap_test_syscalls_access", F_OK) < 0) {
112 if (errno != ECAPMODE)
113 warn("test_syscalls:access");
114 } else
115 warnx("test_syscalls:access succeeded");
116
117 if (acct("/tmp/cap_test_syscalls_acct") < 0) {
118 if (errno != ECAPMODE)
119 warn("test_syscalls:acct");
120 } else
121 warnx("test_syscalls:acct succeeded");
122
123 if (bind(PF_INET, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
124 if (errno != ECAPMODE)
125 warn("test_syscall:bind");
126 } else
127 warnx("test_syscall:bind succeeded");
128
129 if (chdir("/tmp/cap_test_syscalls_chdir") < 0) {
130 if (errno != ECAPMODE)
131 warn("test_syscalls:chdir");
132 } else
133 warnx("test_syscalls:chdir succeeded");
134
135 if (chflags("/tmp/cap_test_syscalls_chflags", UF_NODUMP) < 0) {
136 if (errno != ECAPMODE)
137 warn("test_syscalls:chflags");
138 } else
139 warnx("test_syscalls:chflags succeeded");
140
141 if (chmod("/tmp/cap_test_syscalls_chmod", 0644) < 0) {
142 if (errno != ECAPMODE)
143 warn("test_syscalls:chmod");
144 } else
145 warnx("test_syscalls:chmod succeeded");
146
147 if (chown("/tmp/cap_test_syscalls_chown", -1, -1) < 0) {
148 if (errno != ECAPMODE)
149 warn("test_syscalls:chown");
150 } else
151 warnx("test_syscalls:chown succeeded");
152
153 if (chroot("/tmp/cap_test_syscalls_chroot") < 0) {
154 if (errno != ECAPMODE)
155 warn("test_syscalls:chroot");
156 } else
157 warnx("test_syscalls:chroot succeeded");
158
159 if (close(fd_close)) {
160 if (errno == ECAPMODE)
161 warnx("test_syscalls:close");
162 else
163 warn("test_syscalls:close");
164 }
165
166 if (connect(PF_INET, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
167 if (errno != ECAPMODE)
168 warn("test_syscall:connect");
169 } else
170 warnx("test_syscall:connect succeeded");
171
172 fd = creat("/tmp/cap_test_syscalls_creat", 0644);
173 if (fd >= 0) {
174 warnx("test_syscalls:creat succeeded");
175 close(fd);
176 } else if (errno != ECAPMODE)
177 warn("test_syscalls:creat");
178
179 fd = dup(fd_file);
180 if (fd < 0) {
181 if (errno == ECAPMODE)
182 warnx("test_syscalls:dup");
183 } else
184 close(fd);
185
186 if (fchdir(fd_dir) < 0) {
187 if (errno != ECAPMODE)
188 warn("test_syscall:fchdir");
189 } else
190 warnx("test_syscalls:fchdir succeeded");
191
192 if (fchflags(fd_file, UF_NODUMP) < 0) {
193 if (errno == ECAPMODE)
194 warnx("test_syscall:fchflags");
195 }
196
153 /*
154 * Finally, tests for system calls that don't fit the pattern very well.
155 */
197 pid = fork();
198 if (pid >= 0) {
199 if (pid == 0) {
200 exit(0);
201 } else if (pid > 0) {
202 wpid = waitpid(pid, NULL, 0);
203 if (wpid < 0) {
204 if (errno != ECAPMODE)
156 pid = fork();
157 if (pid >= 0) {
158 if (pid == 0) {
159 exit(0);
160 } else if (pid > 0) {
161 wpid = waitpid(pid, NULL, 0);
162 if (wpid < 0) {
163 if (errno != ECAPMODE)
205 warn("test_syscalls:waitpid");
164 FAIL("capmode:waitpid");
206 } else
165 } else
207 warnx("test_syscalls:waitpid succeeded");
166 FAIL("capmode:waitpid succeeded");
208 }
209 } else
167 }
168 } else
210 warn("test_syscalls:fork");
169 FAIL("capmode:fork");
211
170
212 if (fstat(fd_file, &sb) < 0) {
213 if (errno == ECAPMODE)
214 warnx("test_syscalls:fstat");
215 }
216
217 /*
218 * getegid() can't return an error but check for it anyway.
219 */
220 errno = 0;
221 (void)getegid();
222 if (errno == ECAPMODE)
223 warnx("test_syscalls:getegid");
224
225 /*
226 * geteuid() can't return an error but check for it anyway.
227 */
228 errno = 0;
229 geteuid();
230 if (errno == ECAPMODE)
231 warnx("test_syscalls:geteuid");
232
233 if (getfsstat(&statfs, sizeof(statfs), MNT_NOWAIT) < 0) {
234 if (errno != ECAPMODE)
235 warn("test_syscalls:getfsstat");
236 } else
237 warnx("test_syscalls:getfsstat succeeded");
238
239 /*
240 * getgid() can't return an error but check for it anyway.
241 */
242 errno = 0;
243 getgid();
244 if (errno == ECAPMODE)
245 warnx("test_syscalls:getgid");
246
247 if (getpeername(fd_socket, NULL, NULL) < 0) {
248 if (errno == ECAPMODE)
249 warnx("test_syscalls:getpeername");
250 }
251
252 if (getlogin() == NULL)
171 if (getlogin() == NULL)
253 warn("test_sycalls:getlogin %d", errno);
172 FAIL("test_sycalls:getlogin %d", errno);
254
173
255 /*
256 * getpid() can't return an error but check for it anyway.
257 */
258 errno = 0;
259 (void)getpid();
260 if (errno == ECAPMODE)
261 warnx("test_syscalls:getpid");
262
263 /*
264 * getppid() can't return an error but check for it anyway.
265 */
266 errno = 0;
267 (void)getppid();
268 if (errno == ECAPMODE)
269 warnx("test_syscalls:getppid");
270
271 if (getsockname(fd_socket, NULL, NULL) < 0) {
272 if (errno == ECAPMODE)
174 if (getsockname(fd_socket, NULL, NULL) < 0) {
175 if (errno == ECAPMODE)
273 warnx("test_syscalls:getsockname");
176 FAIL("capmode:getsockname");
274 }
275
177 }
178
276 /*
277 * getuid() can't return an error but check for it anyway.
278 */
279 errno = 0;
280 (void)getuid();
281 if (errno == ECAPMODE)
282 warnx("test_syscalls:getuid");
283
284 /* XXXRW: ktrace */
285
179 /* XXXRW: ktrace */
180
286 if (link("/tmp/foo", "/tmp/bar") < 0) {
287 if (errno != ECAPMODE)
288 warn("test_syscalls:link");
289 } else
290 warnx("test_syscalls:link succeeded");
291
292 ret = lseek(fd_file, SEEK_SET, 0);
293 if (ret < 0) {
294 if (errno == ECAPMODE)
295 warnx("test_syscalls:lseek");
296 else
297 warn("test_syscalls:lseek");
298 }
299
300 if (lstat("/tmp/cap_test_syscalls_lstat", &sb) < 0) {
301 if (errno != ECAPMODE)
302 warn("test_syscalls:lstat");
303 } else
304 warnx("test_syscalls:lstat succeeded");
305
306 if (mknod("/tmp/test_syscalls_mknod", 06440, 0) < 0) {
307 if (errno != ECAPMODE)
308 warn("test_syscalls:mknod");
309 } else
310 warnx("test_syscalls:mknod succeeded");
311
312 /*
313 * mount() is a bit tricky but do our best.
314 */
315 if (mount("procfs", "/not_mounted", 0, NULL) < 0) {
316 if (errno != ECAPMODE)
317 warn("test_syscalls:mount");
318 } else
319 warnx("test_syscalls:mount succeeded");
320
321 if (msync(&fd_file, 8192, MS_ASYNC) < 0) {
322 if (errno == ECAPMODE)
323 warnx("test_syscalls:msync");
324 }
325
326 fd = open("/dev/null", O_RDWR);
327 if (fd >= 0) {
328 warnx("test_syscalls:open succeeded");
329 close(fd);
330 }
331
332 if (pipe(fd2) == 0) {
333 close(fd2[0]);
334 close(fd2[1]);
335 } else if (errno == ECAPMODE)
181 if (pipe(fd2) == 0) {
182 close(fd2[0]);
183 close(fd2[1]);
184 } else if (errno == ECAPMODE)
336 warnx("test_syscalls:pipe");
185 FAIL("capmode:pipe");
337
186
338 if (profil(NULL, 0, 0, 0) < 0) {
339 if (errno == ECAPMODE)
340 warnx("test_syscalls:profile");
341 }
342
343 /* XXXRW: ptrace. */
344
187 /* XXXRW: ptrace. */
188
345 len = read(fd_file, &ch, sizeof(ch));
346 if (len < 0 && errno == ECAPMODE)
347 warnx("test_syscalls:read");
348
349 if (readlink("/tmp/cap_test_syscalls_readlink", NULL, 0) < 0) {
350 if (errno != ECAPMODE)
351 warn("test_syscalls:readlink");
352 } else
353 warnx("test_syscalls:readlink succeeded");
354
355 len = recvfrom(fd_socket, NULL, 0, 0, NULL, NULL);
356 if (len < 0 && errno == ECAPMODE)
357 warnx("test_syscalls:recvfrom");
358
359 len = recvmsg(fd_socket, NULL, 0);
360 if (len < 0 && errno == ECAPMODE)
361 warnx("test_syscalls:recvmsg");
362
363 if (revoke("/tmp/cap_test_syscalls_revoke") < 0) {
364 if (errno != ECAPMODE)
365 warn("test_syscalls:revoke");
366 } else
367 warnx("test_syscalls:revoke succeeded");
368
369 len = sendmsg(fd_socket, NULL, 0);
370 if (len < 0 && errno == ECAPMODE)
371 warnx("test_syscalls:sendmsg");
372
373 len = sendto(fd_socket, NULL, 0, 0, NULL, 0);
374 if (len < 0 && errno == ECAPMODE)
375 warn("test_syscalls:sendto(NULL)");
376
377 if (setuid(getuid()) < 0) {
378 if (errno == ECAPMODE)
379 warnx("test_syscalls:setuid");
380 }
381
382 if (stat("/tmp/cap_test_syscalls_stat", &sb) < 0) {
383 if (errno != ECAPMODE)
384 warn("test_syscalls:stat");
385 } else
386 warnx("test_syscalls:stat succeeded");
387
388 if (symlink("/tmp/cap_test_syscalls_symlink_from",
389 "/tmp/cap_test_syscalls_symlink_to") < 0) {
390 if (errno != ECAPMODE)
391 warn("test_syscalls:symlink");
392 } else
393 warnx("test_syscalls:symlink succeeded");
394
395 /* sysarch() is, by definition, architecture-dependent */
189 /* sysarch() is, by definition, architecture-dependent */
396 if (ARCH_IS("i386") || ARCH_IS("amd64")) {
397 if (sysarch(I386_SET_IOPERM, &sysarch_arg) != -1)
398 warnx("test_syscalls:sysarch succeeded");
399 else if (errno != ECAPMODE)
400 warn("test_syscalls:sysarch errno != ECAPMODE");
190#if defined (__amd64__) || defined (__i386__)
191 CHECK_CAPMODE(sysarch, I386_SET_IOPERM, &sysarch_arg);
192#else
193 /* XXXJA: write a test for arm */
194 FAIL("capmode:no sysarch() test for current architecture");
195#endif
401
196
402 /* XXXJA: write a test for arm */
403 } else {
404 warnx("test_syscalls:no sysarch() test for architecture '%s'", MACHINE);
405 }
406
407 /* XXXRW: No error return from sync(2) to test. */
408
197 /* XXXRW: No error return from sync(2) to test. */
198
409 if (unlink("/tmp/cap_test_syscalls_unlink") < 0) {
410 if (errno != ECAPMODE)
411 warn("test_syscalls:unlink");
412 } else
413 warnx("test_syscalls:unlink succeeded");
414
415 if (unmount("/not_mounted", 0) < 0) {
416 if (errno != ECAPMODE)
417 warn("test_syscalls:unmount");
418 } else
419 warnx("test_syscalls:unmount succeeded");
420
421 len = write(fd_file, &ch, sizeof(ch));
422 if (len < 0 && errno == ECAPMODE)
423 warnx("test_syscalls:write");
424
425 exit(0);
199 return (success);
426}
200}