xref: /freebsd/tests/sys/kern/ktrace_test.c (revision 87b759f0fa1f7554d50ce640c40138512bbded44)
1 /*-
2  * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
3  * Copyright (c) 2023 The FreeBSD Foundation
4  *
5  * This software was developed by Jake Freeland <jfree@FreeBSD.org>
6  * under sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/capsicum.h>
32 #include <sys/cpuset.h>
33 #include <sys/ktrace.h>
34 #include <sys/mman.h>
35 #include <sys/socket.h>
36 #include <sys/syscall.h>
37 #include <sys/sysent.h>
38 #include <sys/time.h>
39 #include <sys/uio.h>
40 #include <sys/user.h>
41 #include <sys/wait.h>
42 
43 #include <machine/sysarch.h>
44 #include <netinet/in.h>
45 
46 #include <atf-c.h>
47 #include <capsicum_helpers.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <netdb.h>
51 #include <signal.h>
52 #include <sysdecode.h>
53 
54 /*
55  * A variant of ATF_REQUIRE that is suitable for use in child
56  * processes.  This only works if the parent process is tripped up by
57  * the early exit and fails some requirement itself.
58  */
59 #define	CHILD_REQUIRE(exp) do {				\
60 	if (!(exp))					\
61 		child_fail_require(__FILE__, __LINE__,	\
62 		    #exp " not met\n");			\
63 } while (0)
64 #define	CHILD_REQUIRE_EQ(actual, expected) do {			\
65 	__typeof__(expected) _e = expected;			\
66 	__typeof__(actual) _a = actual;				\
67 	if (_e != _a)						\
68 		child_fail_require(__FILE__, __LINE__, #actual	\
69 		    " (%jd) == " #expected " (%jd) not met\n",	\
70 		    (intmax_t)_a, (intmax_t)_e);		\
71 } while (0)
72 
73 static __dead2 void
74 child_fail_require(const char *file, int line, const char *fmt, ...)
75 {
76 	va_list ap;
77 	char buf[1024];
78 
79 	/* Use write() not fprintf() to avoid possible duplicate output. */
80 	snprintf(buf, sizeof(buf), "%s:%d: ", file, line);
81 	write(STDERR_FILENO, buf, strlen(buf));
82 	va_start(ap, fmt);
83 	vsnprintf(buf, sizeof(buf), fmt, ap);
84 	write(STDERR_FILENO, buf, strlen(buf));
85 	va_end(ap);
86 
87 	_exit(32);
88 }
89 
90 static void *
91 xmalloc(size_t size)
92 {
93 	void *p;
94 
95 	p = malloc(size);
96 	ATF_REQUIRE(p != NULL);
97 	return (p);
98 }
99 
100 /*
101  * Determine sysdecode ABI based on proc's ABI in sv_flags.
102  */
103 static enum sysdecode_abi
104 syscallabi(u_int sv_flags)
105 {
106 	switch (sv_flags & SV_ABI_MASK) {
107 	case SV_ABI_FREEBSD:
108 		return (SYSDECODE_ABI_FREEBSD);
109 	case SV_ABI_LINUX:
110 #ifdef __LP64__
111 		if ((sv_flags & SV_ILP32) != 0)
112 			return (SYSDECODE_ABI_LINUX32);
113 #endif
114 		return (SYSDECODE_ABI_LINUX);
115 	}
116 	return (SYSDECODE_ABI_UNKNOWN);
117 }
118 
119 static int
120 trace_child(int cpid, int facility, int status)
121 {
122 	int error, fd;
123 
124 	ATF_REQUIRE((fd = open("ktrace.out",
125 	    O_RDONLY | O_CREAT | O_TRUNC, 0600)) != -1);
126 	ATF_REQUIRE_MSG(ktrace("ktrace.out", KTROP_SET, facility, cpid) != -1,
127 	    "ktrace failed: %s", strerror(errno));
128 	/* Notify child that we've starting tracing. */
129 	ATF_REQUIRE(kill(cpid, SIGUSR1) != -1);
130 	/* Wait for child to raise violation and exit. */
131 	ATF_REQUIRE(waitpid(cpid, &error, 0) != -1);
132 	ATF_REQUIRE(WIFEXITED(error));
133 	ATF_REQUIRE_EQ(WEXITSTATUS(error), status);
134 	return (fd);
135 }
136 
137 /*
138  * Start tracing capability violations and notify child that it can execute.
139  * Return @numv capability violations from child in @v.
140  */
141 static void
142 cap_trace_child(pid_t cpid, struct ktr_cap_fail *v, int numv)
143 {
144 	struct ktr_header header;
145 	ssize_t n;
146 	int fd;
147 
148 	fd = trace_child(cpid, KTRFAC_CAPFAIL, 0);
149 
150 	/* Read ktrace header and ensure violation occurred. */
151 	for (int i = 0; i < numv; ++i) {
152 		ATF_REQUIRE((n = read(fd, &header, sizeof(header))) != -1);
153 		ATF_REQUIRE_EQ(n, sizeof(header));
154 		ATF_REQUIRE_EQ(header.ktr_len, sizeof(*v));
155 		ATF_REQUIRE_EQ(header.ktr_pid, cpid);
156 		/* Read the capability violation. */
157 		ATF_REQUIRE((n = read(fd, v + i,
158 		    sizeof(*v))) != -1);
159 		ATF_REQUIRE_EQ(n, sizeof(*v));
160 	}
161 	ATF_REQUIRE(close(fd) != -1);
162 }
163 
164 /*
165  * Test if ktrace will record an operation that is done with
166  * insufficient rights.
167  */
168 ATF_TC_WITHOUT_HEAD(ktrace__cap_not_capable);
169 ATF_TC_BODY(ktrace__cap_not_capable, tc)
170 {
171 	struct ktr_cap_fail violation;
172 	cap_rights_t rights;
173 	sigset_t set = { };
174 	pid_t pid;
175 	int error;
176 
177 	/* Block SIGUSR1 so child does not terminate. */
178 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
179 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
180 
181 	ATF_REQUIRE((pid = fork()) != -1);
182 	if (pid == 0) {
183 		/* Limit fd rights to CAP_READ. */
184 		cap_rights_init(&rights, CAP_READ);
185 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) != -1);
186 		CHILD_REQUIRE(caph_enter() != -1);
187 		/* Wait until ktrace has started. */
188 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
189 		CHILD_REQUIRE_EQ(error, SIGUSR1);
190 		/* Write without CAP_WRITE. */
191 		CHILD_REQUIRE(write(STDIN_FILENO, &pid, sizeof(pid)) == -1);
192 		CHILD_REQUIRE_EQ(errno, ENOTCAPABLE);
193 		exit(0);
194 	}
195 
196 	cap_trace_child(pid, &violation, 1);
197 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_NOTCAPABLE);
198 	ATF_REQUIRE(cap_rights_is_set(&violation.cap_data.cap_needed,
199 	    CAP_WRITE));
200 }
201 
202 /*
203  * Test if ktrace will record an attempt to increase rights.
204  */
205 ATF_TC_WITHOUT_HEAD(ktrace__cap_increase_rights);
206 ATF_TC_BODY(ktrace__cap_increase_rights, tc)
207 {
208 	struct ktr_cap_fail violation;
209 	cap_rights_t rights;
210 	sigset_t set = { };
211 	pid_t pid;
212 	int error;
213 
214 	/* Block SIGUSR1 so child does not terminate. */
215 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
216 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
217 
218 	ATF_REQUIRE((pid = fork()) != -1);
219 	if (pid == 0) {
220 		/* Limit fd rights to CAP_READ. */
221 		cap_rights_init(&rights, CAP_READ);
222 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) != -1);
223 		CHILD_REQUIRE(caph_enter() != -1);
224 		/* Wait until ktrace has started. */
225 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
226 		CHILD_REQUIRE_EQ(error, SIGUSR1);
227 		/* Increase fd rights to include CAP_WRITE. */
228 		cap_rights_set(&rights, CAP_WRITE);
229 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) == -1);
230 		CHILD_REQUIRE_EQ(errno, ENOTCAPABLE);
231 		exit(0);
232 	}
233 
234 	cap_trace_child(pid, &violation, 1);
235 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_INCREASE);
236 	ATF_REQUIRE(cap_rights_is_set(&violation.cap_data.cap_needed,
237 	    CAP_WRITE));
238 }
239 
240 /*
241  * Test if disallowed syscalls are reported as capability violations.
242  */
243 ATF_TC_WITHOUT_HEAD(ktrace__cap_syscall);
244 ATF_TC_BODY(ktrace__cap_syscall, tc)
245 {
246 	struct kinfo_file kinf;
247 	struct ktr_cap_fail violation[2];
248 	sigset_t set = { };
249 	pid_t pid;
250 	int error;
251 
252 	/* Block SIGUSR1 so child does not terminate. */
253 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
254 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
255 
256 	ATF_REQUIRE((pid = fork()) != -1);
257 	if (pid == 0) {
258 		/* Wait until ktrace has started. */
259 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
260 		CHILD_REQUIRE_EQ(error, SIGUSR1);
261 		/* chdir() is not permitted in capability mode. */
262 		CHILD_REQUIRE(chdir(".") != -1);
263 		kinf.kf_structsize = sizeof(struct kinfo_file);
264 		/*
265 		 * fcntl() is permitted in capability mode,
266 		 * but the F_KINFO cmd is not.
267 		 */
268 		CHILD_REQUIRE(fcntl(STDIN_FILENO, F_KINFO, &kinf) != -1);
269 		exit(0);
270 	}
271 
272 	cap_trace_child(pid, violation, 2);
273 	ATF_REQUIRE_EQ(violation[0].cap_type, CAPFAIL_SYSCALL);
274 	error = syscallabi(violation[0].cap_svflags);
275 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[0].cap_code),
276 	    "chdir");
277 
278 	ATF_REQUIRE_EQ(violation[1].cap_type, CAPFAIL_SYSCALL);
279 	error = syscallabi(violation[1].cap_svflags);
280 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[1].cap_code),
281 	    "fcntl");
282 	ATF_REQUIRE_EQ(violation[1].cap_data.cap_int, F_KINFO);
283 }
284 
285 /*
286  * Test if sending a signal to another process is reported as
287  * a signal violation.
288  */
289 ATF_TC_WITHOUT_HEAD(ktrace__cap_signal);
290 ATF_TC_BODY(ktrace__cap_signal, tc)
291 {
292 	struct ktr_cap_fail violation;
293 	sigset_t set = { };
294 	pid_t pid;
295 	int error;
296 
297 	/* Block SIGUSR1 so child does not terminate. */
298 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
299 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
300 
301 	ATF_REQUIRE((pid = fork()) != -1);
302 	if (pid == 0) {
303 		/* Wait until ktrace has started. */
304 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
305 		CHILD_REQUIRE_EQ(error, SIGUSR1);
306 		/*
307 		 * Signals may only be sent to ourself. Sending signals
308 		 * to other processes is not allowed in capability mode.
309 		 */
310 		CHILD_REQUIRE(kill(getppid(), SIGCONT) != -1);
311 		exit(0);
312 	}
313 
314 	cap_trace_child(pid, &violation, 1);
315 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_SIGNAL);
316 	error = syscallabi(violation.cap_svflags);
317 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
318 	    "kill");
319 	ATF_REQUIRE_EQ(violation.cap_data.cap_int, SIGCONT);
320 }
321 
322 /*
323  * Test if opening a socket with a restricted protocol is reported
324  * as a protocol violation.
325  */
326 ATF_TC(ktrace__cap_proto);
327 ATF_TC_HEAD(ktrace__cap_proto, tc)
328 {
329 	atf_tc_set_md_var(tc, "require.user", "root");
330 }
331 ATF_TC_BODY(ktrace__cap_proto, tc)
332 {
333 	struct ktr_cap_fail violation;
334 	sigset_t set = { };
335 	pid_t pid;
336 	int error;
337 
338 	/* Block SIGUSR1 so child does not terminate. */
339 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
340 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
341 
342 	ATF_REQUIRE((pid = fork()) != -1);
343 	if (pid == 0) {
344 		/* Wait until ktrace has started. */
345 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
346 		CHILD_REQUIRE_EQ(error, SIGUSR1);
347 		/*
348 		 * Certain protocols may not be used in capability mode.
349 		 * ICMP's raw-protocol interface is not allowed.
350 		 */
351 		CHILD_REQUIRE(close(socket(AF_INET, SOCK_RAW,
352 		    IPPROTO_ICMP)) != -1);
353 		exit(0);
354 	}
355 
356 	cap_trace_child(pid, &violation, 1);
357 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_PROTO);
358 	error = syscallabi(violation.cap_svflags);
359 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
360 	    "socket");
361 	ATF_REQUIRE_EQ(violation.cap_data.cap_int, IPPROTO_ICMP);
362 }
363 
364 /*
365  * Test if sending data to an address using a socket is
366  * reported as a sockaddr violation.
367  */
368 ATF_TC_WITHOUT_HEAD(ktrace__cap_sockaddr);
369 ATF_TC_BODY(ktrace__cap_sockaddr, tc)
370 {
371 	struct sockaddr_in addr = { }, *saddr;
372 	struct ktr_cap_fail violation;
373 	sigset_t set = { };
374 	pid_t pid;
375 	int error, sfd;
376 
377 	/* Block SIGUSR1 so child does not terminate. */
378 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
379 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
380 
381 	CHILD_REQUIRE((sfd = socket(AF_INET, SOCK_DGRAM,
382 	    IPPROTO_UDP)) != -1);
383 	addr.sin_family = AF_INET;
384 	addr.sin_port = htons(5000);
385 	addr.sin_addr.s_addr = INADDR_ANY;
386 	CHILD_REQUIRE(bind(sfd, (const struct sockaddr *)&addr,
387 	    sizeof(addr)) != -1);
388 
389 	ATF_REQUIRE((pid = fork()) != -1);
390 	if (pid == 0) {
391 		/* Wait until ktrace has started. */
392 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
393 		CHILD_REQUIRE_EQ(error, SIGUSR1);
394 		/*
395 		 * Sending data to an address is not permitted.
396 		 * In this case, sending data to @addr causes a
397 		 * violation.
398 		 */
399 		CHILD_REQUIRE(sendto(sfd, NULL, 0, 0,
400 		    (const struct sockaddr *)&addr, sizeof(addr)) != -1);
401 		exit(0);
402 	}
403 
404 	cap_trace_child(pid, &violation, 1);
405 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_SOCKADDR);
406 	error = syscallabi(violation.cap_svflags);
407 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
408 	    "sendto");
409 	saddr = (struct sockaddr_in *)&violation.cap_data.cap_sockaddr;
410 	ATF_REQUIRE_EQ(saddr->sin_family, AF_INET);
411 	ATF_REQUIRE_EQ(saddr->sin_port, htons(5000));
412 	ATF_REQUIRE_EQ(saddr->sin_addr.s_addr, INADDR_ANY);
413 	close(sfd);
414 }
415 
416 /*
417  * Test if openat() with AT_FDCWD and absolute path are reported
418  * as namei violations.
419  */
420 ATF_TC_WITHOUT_HEAD(ktrace__cap_namei);
421 ATF_TC_BODY(ktrace__cap_namei, tc)
422 {
423 	struct ktr_cap_fail violation[2];
424 	sigset_t set = { };
425 	pid_t pid;
426 	int error;
427 
428 	/* Block SIGUSR1 so child does not terminate. */
429 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
430 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
431 
432 	ATF_REQUIRE((pid = fork()) != -1);
433 	if (pid == 0) {
434 		/* Wait until ktrace has started. */
435 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
436 		CHILD_REQUIRE_EQ(error, SIGUSR1);
437 		/*
438 		 * The AT_FDCWD file descriptor has not been opened
439 		 * and will be inaccessible in capability mode.
440 		 */
441 		CHILD_REQUIRE(close(openat(AT_FDCWD, "ktrace.out",
442 		    O_RDONLY | O_CREAT)) != -1);
443 		/*
444 		 * Absolute paths are inaccessible in capability mode.
445 		 */
446 		CHILD_REQUIRE(close(openat(-1, "/", O_RDONLY)) != -1);
447 		exit(0);
448 	}
449 
450 	cap_trace_child(pid, violation, 2);
451 	ATF_REQUIRE_EQ(violation[0].cap_type, CAPFAIL_NAMEI);
452 	error = syscallabi(violation[0].cap_svflags);
453 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[0].cap_code),
454 	    "openat");
455 	ATF_REQUIRE_STREQ(violation[0].cap_data.cap_path, "AT_FDCWD");
456 
457 	ATF_REQUIRE_EQ(violation[1].cap_type, CAPFAIL_NAMEI);
458 	error = syscallabi(violation[1].cap_svflags);
459 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[1].cap_code),
460 	    "openat");
461 	ATF_REQUIRE_STREQ(violation[1].cap_data.cap_path, "/");
462 }
463 
464 /*
465  * Test if changing another process's cpu set is recorded as
466  * a cpuset violation.
467  */
468 ATF_TC_WITHOUT_HEAD(ktrace__cap_cpuset);
469 ATF_TC_BODY(ktrace__cap_cpuset, tc)
470 {
471 	struct ktr_cap_fail violation;
472 	cpuset_t cpuset_mask = { };
473 	sigset_t set = { };
474 	pid_t pid;
475 	int error;
476 
477 	/* Block SIGUSR1 so child does not terminate. */
478 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
479 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
480 
481 	ATF_REQUIRE((pid = fork()) != -1);
482 	if (pid == 0) {
483 		/* Wait until ktrace has started. */
484 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
485 		CHILD_REQUIRE_EQ(error, SIGUSR1);
486 		/*
487 		 * Set cpu 0 affinity for parent process.
488 		 * Other process's cpu sets are restricted in capability
489 		 * mode, so this will raise a violation.
490 		 */
491 		CPU_SET(0, &cpuset_mask);
492 		CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
493 		    getppid(), sizeof(cpuset_mask), &cpuset_mask) != -1);
494 		exit(0);
495 	}
496 
497 	cap_trace_child(pid, &violation, 1);
498 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_CPUSET);
499 	error = syscallabi(violation.cap_svflags);
500 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
501 	    "cpuset_setaffinity");
502 }
503 
504 ATF_TC_WITHOUT_HEAD(ktrace__cap_shm_open);
505 ATF_TC_BODY(ktrace__cap_shm_open, tc)
506 {
507 	struct ktr_cap_fail violation;
508 	sigset_t set = { };
509 	pid_t pid;
510 	int error;
511 
512 	/* Block SIGUSR1 so child does not terminate. */
513 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
514 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
515 
516 	ATF_REQUIRE((pid = fork()) != -1);
517 	if (pid == 0) {
518 		/* Wait until ktrace has started. */
519 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
520 		CHILD_REQUIRE_EQ(error, SIGUSR1);
521 
522 		CHILD_REQUIRE(shm_open("/ktrace_shm", O_RDWR | O_CREAT,
523 		    0600) != -1);
524 		CHILD_REQUIRE(shm_unlink("/ktrace_shm") != -1);
525 		exit(0);
526 	}
527 
528 	cap_trace_child(pid, &violation, 1);
529 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_NAMEI);
530 	error = syscallabi(violation.cap_svflags);
531 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
532 	    "shm_open2");
533 	ATF_REQUIRE_STREQ(violation.cap_data.cap_path, "/ktrace_shm");
534 }
535 
536 /*
537  * Make sure that ktrace is disabled upon exec of a setuid binary.
538  */
539 ATF_TC(ktrace__setuid_exec);
540 ATF_TC_HEAD(ktrace__setuid_exec, tc)
541 {
542 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
543 }
544 ATF_TC_BODY(ktrace__setuid_exec, tc)
545 {
546 	struct ktr_header header;
547 	struct ktr_syscall *syscall;
548 	sigset_t set = { };
549 	off_t off, off1;
550 	ssize_t n;
551 	pid_t pid;
552 	int error, fd;
553 
554 	/* Block SIGUSR1 so child does not terminate. */
555 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
556 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
557 
558 	ATF_REQUIRE((pid = fork()) != -1);
559 	if (pid == 0) {
560 		/* Wait until ktrace has started. */
561 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
562 		CHILD_REQUIRE_EQ(error, SIGUSR1);
563 
564 		execve("/usr/bin/su", (char *[]){ "su", "whoami", NULL }, NULL);
565 		_exit(0);
566 	}
567 
568 	fd = trace_child(pid, KTRFAC_SYSCALL, 1);
569 
570 	n = read(fd, &header, sizeof(header));
571 	ATF_REQUIRE(n >= 0);
572 	ATF_REQUIRE_EQ((size_t)n, sizeof(header));
573 	ATF_REQUIRE_EQ(header.ktr_pid, pid);
574 	ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall));
575 
576 	syscall = xmalloc(header.ktr_len);
577 	n = read(fd, syscall, header.ktr_len);
578 	ATF_REQUIRE(n >= 0);
579 	ATF_REQUIRE_EQ(n, header.ktr_len);
580 	if (syscall->ktr_code == SYS_sigwait) {
581 		free(syscall);
582 
583 		/* Skip the sigwait() syscall. */
584 		n = read(fd, &header, sizeof(header));
585 		ATF_REQUIRE(n >= 0);
586 		ATF_REQUIRE_EQ((size_t)n, sizeof(header));
587 		ATF_REQUIRE_EQ(header.ktr_pid, pid);
588 		ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall));
589 
590 		syscall = xmalloc(header.ktr_len);
591 		n = read(fd, syscall, header.ktr_len);
592 		ATF_REQUIRE(n >= 0);
593 		ATF_REQUIRE_EQ(n, header.ktr_len);
594 	}
595 	ATF_REQUIRE_EQ(syscall->ktr_code, SYS_execve);
596 	free(syscall);
597 
598 	/* su is setuid root, so this should have been the last entry. */
599 	off = lseek(fd, 0, SEEK_CUR);
600 	ATF_REQUIRE(off != -1);
601 	off1 = lseek(fd, 0, SEEK_END);
602 	ATF_REQUIRE(off1 != -1);
603 	ATF_REQUIRE_EQ(off, off1);
604 
605 	ATF_REQUIRE(close(fd) == 0);
606 }
607 
608 ATF_TP_ADD_TCS(tp)
609 {
610 	ATF_TP_ADD_TC(tp, ktrace__cap_not_capable);
611 	ATF_TP_ADD_TC(tp, ktrace__cap_increase_rights);
612 	ATF_TP_ADD_TC(tp, ktrace__cap_syscall);
613 	ATF_TP_ADD_TC(tp, ktrace__cap_signal);
614 	ATF_TP_ADD_TC(tp, ktrace__cap_proto);
615 	ATF_TP_ADD_TC(tp, ktrace__cap_sockaddr);
616 	ATF_TP_ADD_TC(tp, ktrace__cap_namei);
617 	ATF_TP_ADD_TC(tp, ktrace__cap_cpuset);
618 	ATF_TP_ADD_TC(tp, ktrace__cap_shm_open);
619 	ATF_TP_ADD_TC(tp, ktrace__setuid_exec);
620 	return (atf_no_error());
621 }
622