cap_test_capmode.c revision 221431
1/*-
2 * Copyright (c) 2008-2009 Robert N. M. Watson
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
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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 *
26 * $FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 221431 2011-05-04 12:44:46Z 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>
36__FBSDID("$FreeBSD: head/tools/regression/security/cap_test/cap_test_capmode.c 221431 2011-05-04 12:44:46Z jonathan $");
37
38#include <sys/param.h>
39#include <sys/capability.h>
40#include <sys/mman.h>
41#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>
48#include <netinet/in.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
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
62void
63test_capmode(void)
64{
65	struct sockaddr_in sin;
66	struct statfs statfs;
67	struct stat sb;
68	ssize_t len;
69	long sysarch_arg = 0;
70	int fd, fd_close, fd_dir, fd_file, fd_socket, fd2[2], ret;
71	pid_t pid, wpid;
72	char ch;
73
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");
77
78	fd_close = open("/dev/null", O_RDWR);
79	if (fd_close < 0)
80		err(-1, "test_syscalls:prep: open /dev/null");
81
82	fd_dir = open("/tmp", O_RDONLY);
83	if (fd_dir < 0)
84		err(-1, "test_syscalls:prep: open /tmp");
85
86	fd_socket = socket(PF_INET, SOCK_DGRAM, 0);
87	if (fd_socket < 0)
88		err(-1, "test_syscalls:prep: socket");
89
90	if (cap_enter() < 0)
91		err(-1, "test_syscalls:prep: cap_enter");
92
93
94	bzero(&sin, sizeof(sin));
95	sin.sin_len = sizeof(sin);
96	sin.sin_family = AF_INET;
97
98	/*
99	 * Here begin the tests, sorted roughly alphabetically by system call
100	 * name.
101	 */
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	}
110
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
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)
205					warn("test_syscalls:waitpid");
206			} else
207				warnx("test_syscalls:waitpid succeeded");
208		}
209	} else
210		warn("test_syscalls:fork");
211
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)
253		warn("test_sycalls:getlogin %d", errno);
254
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)
273			warnx("test_syscalls:getsockname");
274	}
275
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
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)
336		warnx("test_syscalls:pipe");
337
338	if (profil(NULL, 0, 0, 0) < 0) {
339		if (errno == ECAPMODE)
340			warnx("test_syscalls:profile");
341	}
342
343	/* XXXRW: ptrace. */
344
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 */
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");
401
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
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);
426}
427