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