From nobody Thu Aug 15 14:30:00 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Wl6w840Lyz5SFgB; Thu, 15 Aug 2024 14:30:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Wl6w82hDpz4NYP; Thu, 15 Aug 2024 14:30:00 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1723732200; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nmnkqjE41dk21fLlV0RlDuYXDEPSbiyl9u7mepDpnLY=; b=u47N2U9DkAoQtoOC1yQQdZImZbIGuDCAYfWB7Y3VLkEjuTjEcK0xVoySgjmxHseLcXHoIi XjB98nrWX091yS4bovWzmlvIuVFBtlXyRs3U/tg1VhToBBSU11vD5OZV3m8EkEShdMaqOe y3Z6siNITqkAHEno3FPioUft/NjP3q5ULmi/OVoFaJpY9sVYWoBhmAGI8zIOtDzGr4kTDc gAXLLcCtMP6MjrlV8vny/x3LCO96IAJlLXDnJzGLH/vqyHZMoHXpfz+b/TpgN3nCfhAc67 Pcl81k5p2Jl6qr3tsCL/4aB6WcMmdSk/Y04y7pF9F7E3E7or4tsW3fBDZy5LbA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1723732200; a=rsa-sha256; cv=none; b=nTT4THSEu82+tKKKySYKipmqh1nb1MPz6EoIfnJTDMjWcM4xTbtMyS1jySMPbXJQaPEUpS 47gNQBPaa4CCbC4b+ta2BSiyyUS76dXIPdlM7zz7VSGaBwygKwX4SvImk7P1FduO8QlRW/ +T2l+9SjyhSuZgkiryhSFP8tQQIVdk9SL+ZY1mtI1br/uulMFYmfchb+P16cq+D5IVVsrS uOq6o4M1F74cI+VoPq7OAnXfh2e16hOSy/b6cRQUwCANiBFjNX+0hDFeDIESLfhrFOyaeW NBTJ+pTj9mmDGV+6hqDpv7tSDmdTGXpTm5hnzm2fl/iacPUi8ZvvhMs5+8lKqw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1723732200; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nmnkqjE41dk21fLlV0RlDuYXDEPSbiyl9u7mepDpnLY=; b=x70CsGbZ3sB+i/Ox5iDF5WEDQFLgtCg4Ysj2gVRfZqUHhKJoAN94zsyCJdhe6y3xDqrB65 Ei0M3ONRDb0UaqX+FOf/Hx6XZzRRKa/T2sBlpZGWCRsqKt4z0aXulDcBN/AncGXrqWgb4b JShioHMvJUKTasTxQXcV/+RALp3dutPAHGb/sk5vOm55cUnocOAjCuxiQz06otpBFRIg/4 ArBkfJnKLuisOAUVKqBkuwjJZBSFhU/o5fejxWXP2SXOPUjcN7/ve/t5FOpEVOEdty201+ Cq+xlESTj6t/47Q+FXUoOo0Gp0mk2zzmsnJmvp9HuhV+HuNTWXG7Fp9bPt6ekw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Wl6w81lxRzR1B; Thu, 15 Aug 2024 14:30:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 47FEU0GE017017; Thu, 15 Aug 2024 14:30:00 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 47FEU09B016996; Thu, 15 Aug 2024 14:30:00 GMT (envelope-from git) Date: Thu, 15 Aug 2024 14:30:00 GMT Message-Id: <202408151430.47FEU09B016996@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 58f9c14235f6 - stable/14 - ktrace tests: Add a test case for handling of exec+setuid binaries List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 58f9c14235f62f8e39992608bec9bd1398eeedff Auto-Submitted: auto-generated The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=58f9c14235f62f8e39992608bec9bd1398eeedff commit 58f9c14235f62f8e39992608bec9bd1398eeedff Author: Mark Johnston AuthorDate: 2024-08-07 15:53:37 +0000 Commit: Mark Johnston CommitDate: 2024-08-15 14:29:49 +0000 ktrace tests: Add a test case for handling of exec+setuid binaries MFC after: 1 week (cherry picked from commit 3852a5a226509551e72c13bce443707f80e863ce) --- tests/sys/kern/ktrace_test.c | 133 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 17 deletions(-) diff --git a/tests/sys/kern/ktrace_test.c b/tests/sys/kern/ktrace_test.c index 9d4c2dbdcd74..dfd60b73a5cd 100644 --- a/tests/sys/kern/ktrace_test.c +++ b/tests/sys/kern/ktrace_test.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,16 @@ child_fail_require(const char *file, int line, const char *fmt, ...) _exit(32); } +static void * +xmalloc(size_t size) +{ + void *p; + + p = malloc(size); + ATF_REQUIRE(p != NULL); + return (p); +} + /* * Determine sysdecode ABI based on proc's ABI in sv_flags. */ @@ -105,36 +116,47 @@ syscallabi(u_int sv_flags) return (SYSDECODE_ABI_UNKNOWN); } -/* - * Start tracing capability violations and notify child that it can execute. - * Return @numv capability violations from child in @v. - */ -static void -cap_trace_child(int cpid, struct ktr_cap_fail *v, int numv) +static int +trace_child(int cpid, int facility, int status) { - struct ktr_header header; - int error, fd, i; + int error, fd; ATF_REQUIRE((fd = open("ktrace.out", O_RDONLY | O_CREAT | O_TRUNC, 0600)) != -1); - ATF_REQUIRE(ktrace("ktrace.out", KTROP_SET, - KTRFAC_CAPFAIL, cpid) != -1); + ATF_REQUIRE_MSG(ktrace("ktrace.out", KTROP_SET, facility, cpid) != -1, + "ktrace failed: %s", strerror(errno)); /* Notify child that we've starting tracing. */ ATF_REQUIRE(kill(cpid, SIGUSR1) != -1); /* Wait for child to raise violation and exit. */ ATF_REQUIRE(waitpid(cpid, &error, 0) != -1); ATF_REQUIRE(WIFEXITED(error)); - ATF_REQUIRE_EQ(WEXITSTATUS(error), 0); + ATF_REQUIRE_EQ(WEXITSTATUS(error), status); + return (fd); +} + +/* + * Start tracing capability violations and notify child that it can execute. + * Return @numv capability violations from child in @v. + */ +static void +cap_trace_child(pid_t cpid, struct ktr_cap_fail *v, int numv) +{ + struct ktr_header header; + ssize_t n; + int fd; + + fd = trace_child(cpid, KTRFAC_CAPFAIL, 0); + /* Read ktrace header and ensure violation occurred. */ - for (i = 0; i < numv; ++i) { - ATF_REQUIRE((error = read(fd, &header, sizeof(header))) != -1); - ATF_REQUIRE_EQ(error, sizeof(header)); + for (int i = 0; i < numv; ++i) { + ATF_REQUIRE((n = read(fd, &header, sizeof(header))) != -1); + ATF_REQUIRE_EQ(n, sizeof(header)); ATF_REQUIRE_EQ(header.ktr_len, sizeof(*v)); ATF_REQUIRE_EQ(header.ktr_pid, cpid); /* Read the capability violation. */ - ATF_REQUIRE((error = read(fd, v + i, + ATF_REQUIRE((n = read(fd, v + i, sizeof(*v))) != -1); - ATF_REQUIRE_EQ(error, sizeof(*v)); + ATF_REQUIRE_EQ(n, sizeof(*v)); } ATF_REQUIRE(close(fd) != -1); } @@ -301,7 +323,11 @@ ATF_TC_BODY(ktrace__cap_signal, tc) * Test if opening a socket with a restricted protocol is reported * as a protocol violation. */ -ATF_TC_WITHOUT_HEAD(ktrace__cap_proto); +ATF_TC(ktrace__cap_proto); +ATF_TC_HEAD(ktrace__cap_proto, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} ATF_TC_BODY(ktrace__cap_proto, tc) { struct ktr_cap_fail violation; @@ -507,6 +533,78 @@ ATF_TC_BODY(ktrace__cap_shm_open, tc) ATF_REQUIRE_STREQ(violation.cap_data.cap_path, "/ktrace_shm"); } +/* + * Make sure that ktrace is disabled upon exec of a setuid binary. + */ +ATF_TC(ktrace__setuid_exec); +ATF_TC_HEAD(ktrace__setuid_exec, tc) +{ + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(ktrace__setuid_exec, tc) +{ + struct ktr_header header; + struct ktr_syscall *syscall; + sigset_t set = { }; + off_t off, off1; + ssize_t n; + pid_t pid; + int error, fd; + + /* Block SIGUSR1 so child does not terminate. */ + ATF_REQUIRE(sigaddset(&set, SIGUSR1) != -1); + ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) != -1); + + ATF_REQUIRE((pid = fork()) != -1); + if (pid == 0) { + /* Wait until ktrace has started. */ + CHILD_REQUIRE(sigwait(&set, &error) != -1); + CHILD_REQUIRE_EQ(error, SIGUSR1); + + execve("/usr/bin/su", (char *[]){ "su", "whoami", NULL }, NULL); + _exit(0); + } + + fd = trace_child(pid, KTRFAC_SYSCALL, 1); + + n = read(fd, &header, sizeof(header)); + ATF_REQUIRE(n >= 0); + ATF_REQUIRE_EQ((size_t)n, sizeof(header)); + ATF_REQUIRE_EQ(header.ktr_pid, pid); + ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall)); + + syscall = xmalloc(header.ktr_len); + n = read(fd, syscall, header.ktr_len); + ATF_REQUIRE(n >= 0); + ATF_REQUIRE_EQ(n, header.ktr_len); + if (syscall->ktr_code == SYS_sigwait) { + free(syscall); + + /* Skip the sigwait() syscall. */ + n = read(fd, &header, sizeof(header)); + ATF_REQUIRE(n >= 0); + ATF_REQUIRE_EQ((size_t)n, sizeof(header)); + ATF_REQUIRE_EQ(header.ktr_pid, pid); + ATF_REQUIRE(header.ktr_len >= (int)sizeof(*syscall)); + + syscall = xmalloc(header.ktr_len); + n = read(fd, syscall, header.ktr_len); + ATF_REQUIRE(n >= 0); + ATF_REQUIRE_EQ(n, header.ktr_len); + } + ATF_REQUIRE_EQ(syscall->ktr_code, SYS_execve); + free(syscall); + + /* su is setuid root, so this should have been the last entry. */ + off = lseek(fd, 0, SEEK_CUR); + ATF_REQUIRE(off != -1); + off1 = lseek(fd, 0, SEEK_END); + ATF_REQUIRE(off1 != -1); + ATF_REQUIRE_EQ(off, off1); + + ATF_REQUIRE(close(fd) == 0); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, ktrace__cap_not_capable); @@ -518,5 +616,6 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, ktrace__cap_namei); ATF_TP_ADD_TC(tp, ktrace__cap_cpuset); ATF_TP_ADD_TC(tp, ktrace__cap_shm_open); + ATF_TP_ADD_TC(tp, ktrace__setuid_exec); return (atf_no_error()); }