xref: /freebsd-src/tests/sys/kern/ktrace_test.c (revision 3852a5a226509551e72c13bce443707f80e863ce)
12f39a986SJake Freeland /*-
22f39a986SJake Freeland  * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
32f39a986SJake Freeland  * Copyright (c) 2023 The FreeBSD Foundation
42f39a986SJake Freeland  *
52f39a986SJake Freeland  * This software was developed by Jake Freeland <jfree@FreeBSD.org>
62f39a986SJake Freeland  * under sponsorship from the FreeBSD Foundation.
72f39a986SJake Freeland  *
82f39a986SJake Freeland  * Redistribution and use in source and binary forms, with or without
92f39a986SJake Freeland  * modification, are permitted provided that the following conditions
102f39a986SJake Freeland  * are met:
112f39a986SJake Freeland  * 1. Redistributions of source code must retain the above copyright
122f39a986SJake Freeland  *    notice, this list of conditions and the following disclaimer.
132f39a986SJake Freeland  * 2. Redistributions in binary form must reproduce the above copyright
142f39a986SJake Freeland  *    notice, this list of conditions and the following disclaimer in the
152f39a986SJake Freeland  *    documentation and/or other materials provided with the distribution.
162f39a986SJake Freeland  *
172f39a986SJake Freeland  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
182f39a986SJake Freeland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
192f39a986SJake Freeland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202f39a986SJake Freeland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
212f39a986SJake Freeland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222f39a986SJake Freeland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232f39a986SJake Freeland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242f39a986SJake Freeland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252f39a986SJake Freeland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262f39a986SJake Freeland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272f39a986SJake Freeland  * SUCH DAMAGE.
282f39a986SJake Freeland  */
292f39a986SJake Freeland 
302f39a986SJake Freeland #include <sys/param.h>
312f39a986SJake Freeland #include <sys/capsicum.h>
322f39a986SJake Freeland #include <sys/cpuset.h>
332f39a986SJake Freeland #include <sys/ktrace.h>
34054a4720SJake Freeland #include <sys/mman.h>
352f39a986SJake Freeland #include <sys/socket.h>
36*3852a5a2SMark Johnston #include <sys/syscall.h>
372f39a986SJake Freeland #include <sys/sysent.h>
382f39a986SJake Freeland #include <sys/time.h>
392f39a986SJake Freeland #include <sys/uio.h>
402f39a986SJake Freeland #include <sys/user.h>
412f39a986SJake Freeland #include <sys/wait.h>
422f39a986SJake Freeland 
432f39a986SJake Freeland #include <machine/sysarch.h>
442f39a986SJake Freeland #include <netinet/in.h>
452f39a986SJake Freeland 
462f39a986SJake Freeland #include <atf-c.h>
472f39a986SJake Freeland #include <capsicum_helpers.h>
482f39a986SJake Freeland #include <errno.h>
492f39a986SJake Freeland #include <fcntl.h>
502f39a986SJake Freeland #include <netdb.h>
512f39a986SJake Freeland #include <signal.h>
522f39a986SJake Freeland #include <sysdecode.h>
532f39a986SJake Freeland 
542f39a986SJake Freeland /*
552f39a986SJake Freeland  * A variant of ATF_REQUIRE that is suitable for use in child
562f39a986SJake Freeland  * processes.  This only works if the parent process is tripped up by
572f39a986SJake Freeland  * the early exit and fails some requirement itself.
582f39a986SJake Freeland  */
592f39a986SJake Freeland #define	CHILD_REQUIRE(exp) do {				\
602f39a986SJake Freeland 	if (!(exp))					\
612f39a986SJake Freeland 		child_fail_require(__FILE__, __LINE__,	\
622f39a986SJake Freeland 		    #exp " not met\n");			\
632f39a986SJake Freeland } while (0)
642f39a986SJake Freeland #define	CHILD_REQUIRE_EQ(actual, expected) do {			\
652f39a986SJake Freeland 	__typeof__(expected) _e = expected;			\
662f39a986SJake Freeland 	__typeof__(actual) _a = actual;				\
672f39a986SJake Freeland 	if (_e != _a)						\
682f39a986SJake Freeland 		child_fail_require(__FILE__, __LINE__, #actual	\
692f39a986SJake Freeland 		    " (%jd) == " #expected " (%jd) not met\n",	\
702f39a986SJake Freeland 		    (intmax_t)_a, (intmax_t)_e);		\
712f39a986SJake Freeland } while (0)
722f39a986SJake Freeland 
732f39a986SJake Freeland static __dead2 void
742f39a986SJake Freeland child_fail_require(const char *file, int line, const char *fmt, ...)
752f39a986SJake Freeland {
762f39a986SJake Freeland 	va_list ap;
772f39a986SJake Freeland 	char buf[1024];
782f39a986SJake Freeland 
792f39a986SJake Freeland 	/* Use write() not fprintf() to avoid possible duplicate output. */
802f39a986SJake Freeland 	snprintf(buf, sizeof(buf), "%s:%d: ", file, line);
812f39a986SJake Freeland 	write(STDERR_FILENO, buf, strlen(buf));
822f39a986SJake Freeland 	va_start(ap, fmt);
832f39a986SJake Freeland 	vsnprintf(buf, sizeof(buf), fmt, ap);
842f39a986SJake Freeland 	write(STDERR_FILENO, buf, strlen(buf));
852f39a986SJake Freeland 	va_end(ap);
862f39a986SJake Freeland 
872f39a986SJake Freeland 	_exit(32);
882f39a986SJake Freeland }
892f39a986SJake Freeland 
90*3852a5a2SMark Johnston static void *
91*3852a5a2SMark Johnston xmalloc(size_t size)
92*3852a5a2SMark Johnston {
93*3852a5a2SMark Johnston 	void *p;
94*3852a5a2SMark Johnston 
95*3852a5a2SMark Johnston 	p = malloc(size);
96*3852a5a2SMark Johnston 	ATF_REQUIRE(p != NULL);
97*3852a5a2SMark Johnston 	return (p);
98*3852a5a2SMark Johnston }
99*3852a5a2SMark Johnston 
1002f39a986SJake Freeland /*
1012f39a986SJake Freeland  * Determine sysdecode ABI based on proc's ABI in sv_flags.
1022f39a986SJake Freeland  */
1032f39a986SJake Freeland static enum sysdecode_abi
1042f39a986SJake Freeland syscallabi(u_int sv_flags)
1052f39a986SJake Freeland {
1062f39a986SJake Freeland 	switch (sv_flags & SV_ABI_MASK) {
1072f39a986SJake Freeland 	case SV_ABI_FREEBSD:
1082f39a986SJake Freeland 		return (SYSDECODE_ABI_FREEBSD);
1092f39a986SJake Freeland 	case SV_ABI_LINUX:
1102f39a986SJake Freeland #ifdef __LP64__
1112f39a986SJake Freeland 		if ((sv_flags & SV_ILP32) != 0)
1122f39a986SJake Freeland 			return (SYSDECODE_ABI_LINUX32);
1132f39a986SJake Freeland #endif
1142f39a986SJake Freeland 		return (SYSDECODE_ABI_LINUX);
1152f39a986SJake Freeland 	}
1162f39a986SJake Freeland 	return (SYSDECODE_ABI_UNKNOWN);
1172f39a986SJake Freeland }
1182f39a986SJake Freeland 
119*3852a5a2SMark Johnston static int
120*3852a5a2SMark Johnston trace_child(int cpid, int facility, int status)
1212f39a986SJake Freeland {
122*3852a5a2SMark Johnston 	int error, fd;
1232f39a986SJake Freeland 
1242f39a986SJake Freeland 	ATF_REQUIRE((fd = open("ktrace.out",
1259cc67e43SMark Johnston 	    O_RDONLY | O_CREAT | O_TRUNC, 0600)) != -1);
126*3852a5a2SMark Johnston 	ATF_REQUIRE_MSG(ktrace("ktrace.out", KTROP_SET, facility, cpid) != -1,
127*3852a5a2SMark Johnston 	    "ktrace failed: %s", strerror(errno));
1282f39a986SJake Freeland 	/* Notify child that we've starting tracing. */
1292f39a986SJake Freeland 	ATF_REQUIRE(kill(cpid, SIGUSR1) != -1);
1302f39a986SJake Freeland 	/* Wait for child to raise violation and exit. */
1312f39a986SJake Freeland 	ATF_REQUIRE(waitpid(cpid, &error, 0) != -1);
1322f39a986SJake Freeland 	ATF_REQUIRE(WIFEXITED(error));
133*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ(WEXITSTATUS(error), status);
134*3852a5a2SMark Johnston 	return (fd);
135*3852a5a2SMark Johnston }
136*3852a5a2SMark Johnston 
137*3852a5a2SMark Johnston /*
138*3852a5a2SMark Johnston  * Start tracing capability violations and notify child that it can execute.
139*3852a5a2SMark Johnston  * Return @numv capability violations from child in @v.
140*3852a5a2SMark Johnston  */
141*3852a5a2SMark Johnston static void
142*3852a5a2SMark Johnston cap_trace_child(pid_t cpid, struct ktr_cap_fail *v, int numv)
143*3852a5a2SMark Johnston {
144*3852a5a2SMark Johnston 	struct ktr_header header;
145*3852a5a2SMark Johnston 	ssize_t n;
146*3852a5a2SMark Johnston 	int fd;
147*3852a5a2SMark Johnston 
148*3852a5a2SMark Johnston 	fd = trace_child(cpid, KTRFAC_CAPFAIL, 0);
149*3852a5a2SMark Johnston 
1502f39a986SJake Freeland 	/* Read ktrace header and ensure violation occurred. */
151*3852a5a2SMark Johnston 	for (int i = 0; i < numv; ++i) {
152*3852a5a2SMark Johnston 		ATF_REQUIRE((n = read(fd, &header, sizeof(header))) != -1);
153*3852a5a2SMark Johnston 		ATF_REQUIRE_EQ(n, sizeof(header));
1542f39a986SJake Freeland 		ATF_REQUIRE_EQ(header.ktr_len, sizeof(*v));
1552f39a986SJake Freeland 		ATF_REQUIRE_EQ(header.ktr_pid, cpid);
1562f39a986SJake Freeland 		/* Read the capability violation. */
157*3852a5a2SMark Johnston 		ATF_REQUIRE((n = read(fd, v + i,
1582f39a986SJake Freeland 		    sizeof(*v))) != -1);
159*3852a5a2SMark Johnston 		ATF_REQUIRE_EQ(n, sizeof(*v));
1602f39a986SJake Freeland 	}
1612f39a986SJake Freeland 	ATF_REQUIRE(close(fd) != -1);
1622f39a986SJake Freeland }
1632f39a986SJake Freeland 
1642f39a986SJake Freeland /*
1652f39a986SJake Freeland  * Test if ktrace will record an operation that is done with
1662f39a986SJake Freeland  * insufficient rights.
1672f39a986SJake Freeland  */
1682f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_not_capable);
1692f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_not_capable, tc)
1702f39a986SJake Freeland {
1712f39a986SJake Freeland 	struct ktr_cap_fail violation;
1722f39a986SJake Freeland 	cap_rights_t rights;
1732f39a986SJake Freeland 	sigset_t set = { };
1742f39a986SJake Freeland 	pid_t pid;
1752f39a986SJake Freeland 	int error;
1762f39a986SJake Freeland 
1772f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
1782f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
1792f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
1802f39a986SJake Freeland 
1812f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
1822f39a986SJake Freeland 	if (pid == 0) {
1832f39a986SJake Freeland 		/* Limit fd rights to CAP_READ. */
1842f39a986SJake Freeland 		cap_rights_init(&rights, CAP_READ);
1852f39a986SJake Freeland 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) != -1);
1862f39a986SJake Freeland 		CHILD_REQUIRE(caph_enter() != -1);
1872f39a986SJake Freeland 		/* Wait until ktrace has started. */
1882f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
1892f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
1902f39a986SJake Freeland 		/* Write without CAP_WRITE. */
1912f39a986SJake Freeland 		CHILD_REQUIRE(write(STDIN_FILENO, &pid, sizeof(pid)) == -1);
1922f39a986SJake Freeland 		CHILD_REQUIRE_EQ(errno, ENOTCAPABLE);
1932f39a986SJake Freeland 		exit(0);
1942f39a986SJake Freeland 	}
1952f39a986SJake Freeland 
1962f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
1972f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_NOTCAPABLE);
1982f39a986SJake Freeland 	ATF_REQUIRE(cap_rights_is_set(&violation.cap_data.cap_needed,
1992f39a986SJake Freeland 	    CAP_WRITE));
2002f39a986SJake Freeland }
2012f39a986SJake Freeland 
2022f39a986SJake Freeland /*
2032f39a986SJake Freeland  * Test if ktrace will record an attempt to increase rights.
2042f39a986SJake Freeland  */
2052f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_increase_rights);
2062f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_increase_rights, tc)
2072f39a986SJake Freeland {
2082f39a986SJake Freeland 	struct ktr_cap_fail violation;
2092f39a986SJake Freeland 	cap_rights_t rights;
2102f39a986SJake Freeland 	sigset_t set = { };
2112f39a986SJake Freeland 	pid_t pid;
2122f39a986SJake Freeland 	int error;
2132f39a986SJake Freeland 
2142f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
2152f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
2162f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
2172f39a986SJake Freeland 
2182f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
2192f39a986SJake Freeland 	if (pid == 0) {
2202f39a986SJake Freeland 		/* Limit fd rights to CAP_READ. */
2212f39a986SJake Freeland 		cap_rights_init(&rights, CAP_READ);
2222f39a986SJake Freeland 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) != -1);
2232f39a986SJake Freeland 		CHILD_REQUIRE(caph_enter() != -1);
2242f39a986SJake Freeland 		/* Wait until ktrace has started. */
2252f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
2262f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
2272f39a986SJake Freeland 		/* Increase fd rights to include CAP_WRITE. */
2282f39a986SJake Freeland 		cap_rights_set(&rights, CAP_WRITE);
2292f39a986SJake Freeland 		CHILD_REQUIRE(caph_rights_limit(STDIN_FILENO, &rights) == -1);
2302f39a986SJake Freeland 		CHILD_REQUIRE_EQ(errno, ENOTCAPABLE);
2312f39a986SJake Freeland 		exit(0);
2322f39a986SJake Freeland 	}
2332f39a986SJake Freeland 
2342f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
2352f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_INCREASE);
2362f39a986SJake Freeland 	ATF_REQUIRE(cap_rights_is_set(&violation.cap_data.cap_needed,
2372f39a986SJake Freeland 	    CAP_WRITE));
2382f39a986SJake Freeland }
2392f39a986SJake Freeland 
2402f39a986SJake Freeland /*
2412f39a986SJake Freeland  * Test if disallowed syscalls are reported as capability violations.
2422f39a986SJake Freeland  */
2432f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_syscall);
2442f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_syscall, tc)
2452f39a986SJake Freeland {
2462f39a986SJake Freeland 	struct kinfo_file kinf;
2472f39a986SJake Freeland 	struct ktr_cap_fail violation[2];
2482f39a986SJake Freeland 	sigset_t set = { };
2492f39a986SJake Freeland 	pid_t pid;
2502f39a986SJake Freeland 	int error;
2512f39a986SJake Freeland 
2522f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
2532f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
2542f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
2552f39a986SJake Freeland 
2562f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
2572f39a986SJake Freeland 	if (pid == 0) {
2582f39a986SJake Freeland 		/* Wait until ktrace has started. */
2592f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
2602f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
2612f39a986SJake Freeland 		/* chdir() is not permitted in capability mode. */
2622f39a986SJake Freeland 		CHILD_REQUIRE(chdir(".") != -1);
2632f39a986SJake Freeland 		kinf.kf_structsize = sizeof(struct kinfo_file);
2642f39a986SJake Freeland 		/*
2652f39a986SJake Freeland 		 * fcntl() is permitted in capability mode,
2662f39a986SJake Freeland 		 * but the F_KINFO cmd is not.
2672f39a986SJake Freeland 		 */
2682f39a986SJake Freeland 		CHILD_REQUIRE(fcntl(STDIN_FILENO, F_KINFO, &kinf) != -1);
2692f39a986SJake Freeland 		exit(0);
2702f39a986SJake Freeland 	}
2712f39a986SJake Freeland 
2722f39a986SJake Freeland 	cap_trace_child(pid, violation, 2);
2732f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation[0].cap_type, CAPFAIL_SYSCALL);
2742f39a986SJake Freeland 	error = syscallabi(violation[0].cap_svflags);
2752f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[0].cap_code),
2762f39a986SJake Freeland 	    "chdir");
2772f39a986SJake Freeland 
2782f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation[1].cap_type, CAPFAIL_SYSCALL);
2792f39a986SJake Freeland 	error = syscallabi(violation[1].cap_svflags);
2802f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[1].cap_code),
2812f39a986SJake Freeland 	    "fcntl");
2822f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation[1].cap_data.cap_int, F_KINFO);
2832f39a986SJake Freeland }
2842f39a986SJake Freeland 
2852f39a986SJake Freeland /*
2862f39a986SJake Freeland  * Test if sending a signal to another process is reported as
2872f39a986SJake Freeland  * a signal violation.
2882f39a986SJake Freeland  */
2892f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_signal);
2902f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_signal, tc)
2912f39a986SJake Freeland {
2922f39a986SJake Freeland 	struct ktr_cap_fail violation;
2932f39a986SJake Freeland 	sigset_t set = { };
2942f39a986SJake Freeland 	pid_t pid;
2952f39a986SJake Freeland 	int error;
2962f39a986SJake Freeland 
2972f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
2982f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
2992f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
3002f39a986SJake Freeland 
3012f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
3022f39a986SJake Freeland 	if (pid == 0) {
3032f39a986SJake Freeland 		/* Wait until ktrace has started. */
3042f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
3052f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
3062f39a986SJake Freeland 		/*
3072f39a986SJake Freeland 		 * Signals may only be sent to ourself. Sending signals
3082f39a986SJake Freeland 		 * to other processes is not allowed in capability mode.
3092f39a986SJake Freeland 		 */
3102f39a986SJake Freeland 		CHILD_REQUIRE(kill(getppid(), SIGCONT) != -1);
3112f39a986SJake Freeland 		exit(0);
3122f39a986SJake Freeland 	}
3132f39a986SJake Freeland 
3142f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
3152f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_SIGNAL);
3162f39a986SJake Freeland 	error = syscallabi(violation.cap_svflags);
3172f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
3182f39a986SJake Freeland 	    "kill");
3192f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_data.cap_int, SIGCONT);
3202f39a986SJake Freeland }
3212f39a986SJake Freeland 
3222f39a986SJake Freeland /*
3232f39a986SJake Freeland  * Test if opening a socket with a restricted protocol is reported
3242f39a986SJake Freeland  * as a protocol violation.
3252f39a986SJake Freeland  */
326*3852a5a2SMark Johnston ATF_TC(ktrace__cap_proto);
327*3852a5a2SMark Johnston ATF_TC_HEAD(ktrace__cap_proto, tc)
328*3852a5a2SMark Johnston {
329*3852a5a2SMark Johnston 	atf_tc_set_md_var(tc, "require.user", "root");
330*3852a5a2SMark Johnston }
3312f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_proto, tc)
3322f39a986SJake Freeland {
3332f39a986SJake Freeland 	struct ktr_cap_fail violation;
3342f39a986SJake Freeland 	sigset_t set = { };
3352f39a986SJake Freeland 	pid_t pid;
3362f39a986SJake Freeland 	int error;
3372f39a986SJake Freeland 
3382f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
3392f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
3402f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
3412f39a986SJake Freeland 
3422f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
3432f39a986SJake Freeland 	if (pid == 0) {
3442f39a986SJake Freeland 		/* Wait until ktrace has started. */
3452f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
3462f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
3472f39a986SJake Freeland 		/*
3482f39a986SJake Freeland 		 * Certain protocols may not be used in capability mode.
3492f39a986SJake Freeland 		 * ICMP's raw-protocol interface is not allowed.
3502f39a986SJake Freeland 		 */
3512f39a986SJake Freeland 		CHILD_REQUIRE(close(socket(AF_INET, SOCK_RAW,
3522f39a986SJake Freeland 		    IPPROTO_ICMP)) != -1);
3532f39a986SJake Freeland 		exit(0);
3542f39a986SJake Freeland 	}
3552f39a986SJake Freeland 
3562f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
3572f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_PROTO);
3582f39a986SJake Freeland 	error = syscallabi(violation.cap_svflags);
3592f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
3602f39a986SJake Freeland 	    "socket");
3612f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_data.cap_int, IPPROTO_ICMP);
3622f39a986SJake Freeland }
3632f39a986SJake Freeland 
3642f39a986SJake Freeland /*
3652f39a986SJake Freeland  * Test if sending data to an address using a socket is
3662f39a986SJake Freeland  * reported as a sockaddr violation.
3672f39a986SJake Freeland  */
3682f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_sockaddr);
3692f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_sockaddr, tc)
3702f39a986SJake Freeland {
3712f39a986SJake Freeland 	struct sockaddr_in addr = { }, *saddr;
3722f39a986SJake Freeland 	struct ktr_cap_fail violation;
3732f39a986SJake Freeland 	sigset_t set = { };
3742f39a986SJake Freeland 	pid_t pid;
3752f39a986SJake Freeland 	int error, sfd;
3762f39a986SJake Freeland 
3772f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
3782f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
3792f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
3802f39a986SJake Freeland 
3812f39a986SJake Freeland 	CHILD_REQUIRE((sfd = socket(AF_INET, SOCK_DGRAM,
3822f39a986SJake Freeland 	    IPPROTO_UDP)) != -1);
3832f39a986SJake Freeland 	addr.sin_family = AF_INET;
3842f39a986SJake Freeland 	addr.sin_port = htons(5000);
3852f39a986SJake Freeland 	addr.sin_addr.s_addr = INADDR_ANY;
3862f39a986SJake Freeland 	CHILD_REQUIRE(bind(sfd, (const struct sockaddr *)&addr,
3872f39a986SJake Freeland 	    sizeof(addr)) != -1);
3882f39a986SJake Freeland 
3892f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
3902f39a986SJake Freeland 	if (pid == 0) {
3912f39a986SJake Freeland 		/* Wait until ktrace has started. */
3922f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
3932f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
3942f39a986SJake Freeland 		/*
3952f39a986SJake Freeland 		 * Sending data to an address is not permitted.
3962f39a986SJake Freeland 		 * In this case, sending data to @addr causes a
3972f39a986SJake Freeland 		 * violation.
3982f39a986SJake Freeland 		 */
3992f39a986SJake Freeland 		CHILD_REQUIRE(sendto(sfd, NULL, 0, 0,
4002f39a986SJake Freeland 		    (const struct sockaddr *)&addr, sizeof(addr)) != -1);
4012f39a986SJake Freeland 		exit(0);
4022f39a986SJake Freeland 	}
4032f39a986SJake Freeland 
4042f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
4052f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_SOCKADDR);
4062f39a986SJake Freeland 	error = syscallabi(violation.cap_svflags);
4072f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
4082f39a986SJake Freeland 	    "sendto");
4092f39a986SJake Freeland 	saddr = (struct sockaddr_in *)&violation.cap_data.cap_sockaddr;
4102f39a986SJake Freeland 	ATF_REQUIRE_EQ(saddr->sin_family, AF_INET);
4112f39a986SJake Freeland 	ATF_REQUIRE_EQ(saddr->sin_port, htons(5000));
4122f39a986SJake Freeland 	ATF_REQUIRE_EQ(saddr->sin_addr.s_addr, INADDR_ANY);
4132f39a986SJake Freeland 	close(sfd);
4142f39a986SJake Freeland }
4152f39a986SJake Freeland 
4162f39a986SJake Freeland /*
4172f39a986SJake Freeland  * Test if openat() with AT_FDCWD and absolute path are reported
4182f39a986SJake Freeland  * as namei violations.
4192f39a986SJake Freeland  */
4202f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_namei);
4212f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_namei, tc)
4222f39a986SJake Freeland {
4232f39a986SJake Freeland 	struct ktr_cap_fail violation[2];
4242f39a986SJake Freeland 	sigset_t set = { };
4252f39a986SJake Freeland 	pid_t pid;
4262f39a986SJake Freeland 	int error;
4272f39a986SJake Freeland 
4282f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
4292f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
4302f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
4312f39a986SJake Freeland 
4322f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
4332f39a986SJake Freeland 	if (pid == 0) {
4342f39a986SJake Freeland 		/* Wait until ktrace has started. */
4352f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
4362f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
4372f39a986SJake Freeland 		/*
4382f39a986SJake Freeland 		 * The AT_FDCWD file descriptor has not been opened
4392f39a986SJake Freeland 		 * and will be inaccessible in capability mode.
4402f39a986SJake Freeland 		 */
4412f39a986SJake Freeland 		CHILD_REQUIRE(close(openat(AT_FDCWD, "ktrace.out",
4422f39a986SJake Freeland 		    O_RDONLY | O_CREAT)) != -1);
4432f39a986SJake Freeland 		/*
4442f39a986SJake Freeland 		 * Absolute paths are inaccessible in capability mode.
4452f39a986SJake Freeland 		 */
4462f39a986SJake Freeland 		CHILD_REQUIRE(close(openat(-1, "/", O_RDONLY)) != -1);
4472f39a986SJake Freeland 		exit(0);
4482f39a986SJake Freeland 	}
4492f39a986SJake Freeland 
4502f39a986SJake Freeland 	cap_trace_child(pid, violation, 2);
4512f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation[0].cap_type, CAPFAIL_NAMEI);
4522f39a986SJake Freeland 	error = syscallabi(violation[0].cap_svflags);
4532f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[0].cap_code),
4542f39a986SJake Freeland 	    "openat");
4552f39a986SJake Freeland 	ATF_REQUIRE_STREQ(violation[0].cap_data.cap_path, "AT_FDCWD");
4562f39a986SJake Freeland 
4572f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation[1].cap_type, CAPFAIL_NAMEI);
4582f39a986SJake Freeland 	error = syscallabi(violation[1].cap_svflags);
4592f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation[1].cap_code),
4602f39a986SJake Freeland 	    "openat");
4612f39a986SJake Freeland 	ATF_REQUIRE_STREQ(violation[1].cap_data.cap_path, "/");
4622f39a986SJake Freeland }
4632f39a986SJake Freeland 
4642f39a986SJake Freeland /*
4652f39a986SJake Freeland  * Test if changing another process's cpu set is recorded as
4662f39a986SJake Freeland  * a cpuset violation.
4672f39a986SJake Freeland  */
4682f39a986SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_cpuset);
4692f39a986SJake Freeland ATF_TC_BODY(ktrace__cap_cpuset, tc)
4702f39a986SJake Freeland {
4712f39a986SJake Freeland 	struct ktr_cap_fail violation;
4722f39a986SJake Freeland 	cpuset_t cpuset_mask = { };
4732f39a986SJake Freeland 	sigset_t set = { };
4742f39a986SJake Freeland 	pid_t pid;
4752f39a986SJake Freeland 	int error;
4762f39a986SJake Freeland 
4772f39a986SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
4782f39a986SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
4792f39a986SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
4802f39a986SJake Freeland 
4812f39a986SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
4822f39a986SJake Freeland 	if (pid == 0) {
4832f39a986SJake Freeland 		/* Wait until ktrace has started. */
4842f39a986SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
4852f39a986SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
4862f39a986SJake Freeland 		/*
4872f39a986SJake Freeland 		 * Set cpu 0 affinity for parent process.
4882f39a986SJake Freeland 		 * Other process's cpu sets are restricted in capability
4892f39a986SJake Freeland 		 * mode, so this will raise a violation.
4902f39a986SJake Freeland 		 */
4912f39a986SJake Freeland 		CPU_SET(0, &cpuset_mask);
4922f39a986SJake Freeland 		CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
4932f39a986SJake Freeland 		    getppid(), sizeof(cpuset_mask), &cpuset_mask) != -1);
4942f39a986SJake Freeland 		exit(0);
4952f39a986SJake Freeland 	}
4962f39a986SJake Freeland 
4972f39a986SJake Freeland 	cap_trace_child(pid, &violation, 1);
4982f39a986SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_CPUSET);
4992f39a986SJake Freeland 	error = syscallabi(violation.cap_svflags);
5002f39a986SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
5012f39a986SJake Freeland 	    "cpuset_setaffinity");
5022f39a986SJake Freeland }
5032f39a986SJake Freeland 
504054a4720SJake Freeland ATF_TC_WITHOUT_HEAD(ktrace__cap_shm_open);
505054a4720SJake Freeland ATF_TC_BODY(ktrace__cap_shm_open, tc)
506054a4720SJake Freeland {
507054a4720SJake Freeland 	struct ktr_cap_fail violation;
508054a4720SJake Freeland 	sigset_t set = { };
509054a4720SJake Freeland 	pid_t pid;
510054a4720SJake Freeland 	int error;
511054a4720SJake Freeland 
512054a4720SJake Freeland 	/* Block SIGUSR1 so child does not terminate. */
513054a4720SJake Freeland 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
514054a4720SJake Freeland 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
515054a4720SJake Freeland 
516054a4720SJake Freeland 	ATF_REQUIRE((pid = fork()) != -1);
517054a4720SJake Freeland 	if (pid == 0) {
518054a4720SJake Freeland 		/* Wait until ktrace has started. */
519054a4720SJake Freeland 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
520054a4720SJake Freeland 		CHILD_REQUIRE_EQ(error, SIGUSR1);
521054a4720SJake Freeland 
522054a4720SJake Freeland 		CHILD_REQUIRE(shm_open("/ktrace_shm", O_RDWR | O_CREAT,
523054a4720SJake Freeland 		    0600) != -1);
524054a4720SJake Freeland 		CHILD_REQUIRE(shm_unlink("/ktrace_shm") != -1);
525054a4720SJake Freeland 		exit(0);
526054a4720SJake Freeland 	}
527054a4720SJake Freeland 
528054a4720SJake Freeland 	cap_trace_child(pid, &violation, 1);
529054a4720SJake Freeland 	ATF_REQUIRE_EQ(violation.cap_type, CAPFAIL_NAMEI);
530054a4720SJake Freeland 	error = syscallabi(violation.cap_svflags);
531054a4720SJake Freeland 	ATF_REQUIRE_STREQ(sysdecode_syscallname(error, violation.cap_code),
532054a4720SJake Freeland 	    "shm_open2");
533054a4720SJake Freeland 	ATF_REQUIRE_STREQ(violation.cap_data.cap_path, "/ktrace_shm");
534054a4720SJake Freeland }
535054a4720SJake Freeland 
536*3852a5a2SMark Johnston /*
537*3852a5a2SMark Johnston  * Make sure that ktrace is disabled upon exec of a setuid binary.
538*3852a5a2SMark Johnston  */
539*3852a5a2SMark Johnston ATF_TC(ktrace__setuid_exec);
540*3852a5a2SMark Johnston ATF_TC_HEAD(ktrace__setuid_exec, tc)
541*3852a5a2SMark Johnston {
542*3852a5a2SMark Johnston 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
543*3852a5a2SMark Johnston }
544*3852a5a2SMark Johnston ATF_TC_BODY(ktrace__setuid_exec, tc)
545*3852a5a2SMark Johnston {
546*3852a5a2SMark Johnston 	struct ktr_header header;
547*3852a5a2SMark Johnston 	struct ktr_syscall *syscall;
548*3852a5a2SMark Johnston 	sigset_t set = { };
549*3852a5a2SMark Johnston 	off_t off, off1;
550*3852a5a2SMark Johnston 	ssize_t n;
551*3852a5a2SMark Johnston 	pid_t pid;
552*3852a5a2SMark Johnston 	int error, fd;
553*3852a5a2SMark Johnston 
554*3852a5a2SMark Johnston 	/* Block SIGUSR1 so child does not terminate. */
555*3852a5a2SMark Johnston 	ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1);
556*3852a5a2SMark Johnston 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
557*3852a5a2SMark Johnston 
558*3852a5a2SMark Johnston 	ATF_REQUIRE((pid = fork()) != -1);
559*3852a5a2SMark Johnston 	if (pid == 0) {
560*3852a5a2SMark Johnston 		/* Wait until ktrace has started. */
561*3852a5a2SMark Johnston 		CHILD_REQUIRE(sigwait(&set, &error) != -1);
562*3852a5a2SMark Johnston 		CHILD_REQUIRE_EQ(error, SIGUSR1);
563*3852a5a2SMark Johnston 
564*3852a5a2SMark Johnston 		execve("/usr/bin/su", (char *[]){ "su", "whoami", NULL }, NULL);
565*3852a5a2SMark Johnston 		_exit(0);
566*3852a5a2SMark Johnston 	}
567*3852a5a2SMark Johnston 
568*3852a5a2SMark Johnston 	fd = trace_child(pid, KTRFAC_SYSCALL, 1);
569*3852a5a2SMark Johnston 
570*3852a5a2SMark Johnston 	n = read(fd, &header, sizeof(header));
571*3852a5a2SMark Johnston 	ATF_REQUIRE(n >= 0);
572*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ((size_t)n, sizeof(header));
573*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ(header.ktr_pid, pid);
574*3852a5a2SMark Johnston 	ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall));
575*3852a5a2SMark Johnston 
576*3852a5a2SMark Johnston 	syscall = xmalloc(header.ktr_len);
577*3852a5a2SMark Johnston 	n = read(fd, syscall, header.ktr_len);
578*3852a5a2SMark Johnston 	ATF_REQUIRE(n >= 0);
579*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ(n, header.ktr_len);
580*3852a5a2SMark Johnston 	if (syscall->ktr_code == SYS_sigwait) {
581*3852a5a2SMark Johnston 		free(syscall);
582*3852a5a2SMark Johnston 
583*3852a5a2SMark Johnston 		/* Skip the sigwait() syscall. */
584*3852a5a2SMark Johnston 		n = read(fd, &header, sizeof(header));
585*3852a5a2SMark Johnston 		ATF_REQUIRE(n >= 0);
586*3852a5a2SMark Johnston 		ATF_REQUIRE_EQ((size_t)n, sizeof(header));
587*3852a5a2SMark Johnston 		ATF_REQUIRE_EQ(header.ktr_pid, pid);
588*3852a5a2SMark Johnston 		ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall));
589*3852a5a2SMark Johnston 
590*3852a5a2SMark Johnston 		syscall = xmalloc(header.ktr_len);
591*3852a5a2SMark Johnston 		n = read(fd, syscall, header.ktr_len);
592*3852a5a2SMark Johnston 		ATF_REQUIRE(n >= 0);
593*3852a5a2SMark Johnston 		ATF_REQUIRE_EQ(n, header.ktr_len);
594*3852a5a2SMark Johnston 	}
595*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ(syscall->ktr_code, SYS_execve);
596*3852a5a2SMark Johnston 	free(syscall);
597*3852a5a2SMark Johnston 
598*3852a5a2SMark Johnston 	/* su is setuid root, so this should have been the last entry. */
599*3852a5a2SMark Johnston 	off = lseek(fd, 0, SEEK_CUR);
600*3852a5a2SMark Johnston 	ATF_REQUIRE(off != -1);
601*3852a5a2SMark Johnston 	off1 = lseek(fd, 0, SEEK_END);
602*3852a5a2SMark Johnston 	ATF_REQUIRE(off1 != -1);
603*3852a5a2SMark Johnston 	ATF_REQUIRE_EQ(off, off1);
604*3852a5a2SMark Johnston 
605*3852a5a2SMark Johnston 	ATF_REQUIRE(close(fd) == 0);
606*3852a5a2SMark Johnston }
607*3852a5a2SMark Johnston 
6082f39a986SJake Freeland ATF_TP_ADD_TCS(tp)
6092f39a986SJake Freeland {
6102f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_not_capable);
6112f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_increase_rights);
6122f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_syscall);
6132f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_signal);
6142f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_proto);
6152f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_sockaddr);
6162f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_namei);
6172f39a986SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_cpuset);
618054a4720SJake Freeland 	ATF_TP_ADD_TC(tp, ktrace__cap_shm_open);
619*3852a5a2SMark Johnston 	ATF_TP_ADD_TC(tp, ktrace__setuid_exec);
6202f39a986SJake Freeland 	return (atf_no_error());
6212f39a986SJake Freeland }
622