Date: Fri, 12 Jun 2026 16:00:57 +0000 From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: fe03a78c5d59 - main - tests/jaildesc: Add some more test scenarios Message-ID: <6a2c2d39.37799.5d17f769@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=fe03a78c5d5966992c8df482d984bae83dc92b45 commit fe03a78c5d5966992c8df482d984bae83dc92b45 Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2026-06-12 14:58:19 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2026-06-12 14:58:19 +0000 tests/jaildesc: Add some more test scenarios MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D57147 --- tests/sys/kern/Makefile | 2 +- tests/sys/kern/jaildesc.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 1 deletion(-) diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index fb267f1a2782..3b09ee3181d2 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -95,7 +95,7 @@ PROGS+= sendfile_helper LIBADD.aslr+= util LIBADD.copy_file_range+= md LIBADD.jail_lookup_root+= jail util -LIBADD.jaildesc+= pthread +LIBADD.jaildesc+= kvm pthread LIBADD.ssl_sendfile+= pthread crypto ssl CFLAGS.sys_getrandom+= -I${SRCTOP}/sys/contrib/zstd/lib LIBADD.sys_getrandom+= zstd diff --git a/tests/sys/kern/jaildesc.c b/tests/sys/kern/jaildesc.c index 11d751554887..cfdd1529fdfa 100644 --- a/tests/sys/kern/jaildesc.c +++ b/tests/sys/kern/jaildesc.c @@ -6,16 +6,56 @@ #include <sys/param.h> #include <sys/jail.h> +#include <sys/sysctl.h> +#include <sys/wait.h> #include <sys/uio.h> +#include <sys/user.h> #include <atf-c.h> #include <errno.h> +#include <fcntl.h> #include <poll.h> #include <pthread.h> #include <pwd.h> +#include <signal.h> #include <string.h> #include <unistd.h> +#include <kvm.h> + +/* + * Block until a thread in the specified process is sleeping in the specified + * wait message. + */ +static void +wait_for_naptime(pid_t pid, const char *wmesg) +{ + kvm_t *kd; + int count; + + kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, NULL); + ATF_REQUIRE(kd != NULL); + for (;;) { + struct kinfo_proc *kip; + int i; + + usleep(1000); + kip = kvm_getprocs(kd, KERN_PROC_PID | KERN_PROC_INC_THREAD, + pid, &count); + ATF_REQUIRE(kip != NULL); + for (i = 0; i < count; i++) { + ATF_REQUIRE(kip[i].ki_stat != SZOMB); + if (kip[i].ki_stat == SSLEEP && + strcmp(kip[i].ki_wmesg, wmesg) == 0) + break; + } + if (i < count) + break; + } + + kvm_close(kd); +} + /* * Create a persistent jail and return an owning descriptor for it. * The jail is removed when the returned descriptor is closed. @@ -191,11 +231,175 @@ ATF_TC_BODY(poll_close_race_get_desc, tc) ATF_REQUIRE_MSG(close(owning_jd) == 0, "close: %s", strerror(errno)); } +/* + * Verify that a process inside a jail cannot obtain a jail descriptor for + * its own jail. + */ +ATF_TC(curjail_get); +ATF_TC_HEAD(curjail_get, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(curjail_get, tc) +{ + char namebuf[MAXHOSTNAMELEN]; + struct iovec iov[4]; + int desc, error, jid, n; + + (void)create_jail("jaildesc_get_desc_current_jail"); + + strlcpy(namebuf, "jaildesc_get_desc_current_jail", sizeof(namebuf)); + jid = -1; + n = 0; + iov[n].iov_base = __DECONST(void *, "name"); + iov[n++].iov_len = sizeof("name"); + iov[n].iov_base = namebuf; + iov[n++].iov_len = strlen(namebuf) + 1; + jid = jail_get(iov, n, 0); + ATF_REQUIRE_MSG(jid >= 0, "jail_get: %s", strerror(errno)); + + error = jail_attach(jid); + ATF_REQUIRE_MSG(error == 0, "jail_attach: %s", strerror(errno)); + + /* + * Now that we are inside the jail, verify that we cannot obtain a + * descriptor for it. + */ + strlcpy(namebuf, "jaildesc_get_desc_current_jail", sizeof(namebuf)); + desc = -1; + n = 0; + iov[n].iov_base = __DECONST(void *, "name"); + iov[n++].iov_len = sizeof("name"); + iov[n].iov_base = namebuf; + iov[n++].iov_len = strlen(namebuf) + 1; + iov[n].iov_base = __DECONST(void *, "desc"); + iov[n++].iov_len = sizeof("desc"); + iov[n].iov_base = &desc; + iov[n++].iov_len = sizeof(desc); + ATF_REQUIRE_MSG(jail_get(iov, n, JAIL_GET_DESC) == -1, + "jail_get succeeded unexpectedly"); + ATF_REQUIRE_MSG(jail_get(iov, n, JAIL_OWN_DESC) == -1, + "jail_get succeeded unexpectedly"); +} + +static void +nop(int signum __unused) +{ +} + +/* + * Close an owning descriptor while in the corresponding jail. + */ +ATF_TC(self_destruct); +ATF_TC_HEAD(self_destruct, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(self_destruct, tc) +{ + int error, jd, status; + pid_t pid; + + jd = create_jail("jaildesc_self_destruct"); + + pid = fork(); + ATF_REQUIRE_MSG(pid >= 0, "fork: %s", strerror(errno)); + if (pid == 0) { + struct sigaction sa; + + error = jail_attach_jd(jd); + if (error != 0) + _exit(1); + + sa.sa_handler = nop; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + error = sigaction(SIGALRM, &sa, NULL); + if (error != 0) + _exit(2); + + pause(); + close(jd); + /* NOTREACHED? */ + _exit(3); + } + + wait_for_naptime(pid, "sigsusp"); + + error = close(jd); + ATF_REQUIRE_MSG(error == 0, "close: %s", strerror(errno)); + + error = kill(pid, SIGALRM); + ATF_REQUIRE_MSG(error == 0, "kill: %s", strerror(errno)); + + pid = waitpid(pid, &status, 0); + ATF_REQUIRE_MSG(pid >= 0, "waitpid: %s", strerror(errno)); + ATF_REQUIRE(WIFSIGNALED(status)); + ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL); +} + +/* + * Try to get an fd for a non-existent jail. + */ +ATF_TC(at_desc_bad_fd); +ATF_TC_HEAD(at_desc_bad_fd, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(at_desc_bad_fd, tc) +{ + int jd, status; + pid_t pid; + + jd = create_jail("jaildesc_at_desc_bad_fd"); + + pid = fork(); + ATF_REQUIRE_MSG(pid >= 0, "fork: %s", strerror(errno)); + if (pid == 0) { + struct iovec iov[4]; + char namebuf[MAXHOSTNAMELEN]; + int desc, i, n; + + if (jail_attach_jd(jd) != 0) + _exit(1); + + /* Regression test: loop here to trigger a refcount leak. */ + for (i = 0; i < 100; i++) { + strlcpy(namebuf, "nonexistent", sizeof(namebuf)); + desc = STDIN_FILENO; + n = 0; + iov[n].iov_base = __DECONST(void *, "name"); + iov[n++].iov_len = strlen("name") + 1; + iov[n].iov_base = namebuf; + iov[n++].iov_len = sizeof(namebuf); + iov[n].iov_base = __DECONST(void *, "desc"); + iov[n++].iov_len = strlen("desc") + 1; + iov[n].iov_base = &desc; + iov[n++].iov_len = sizeof(desc); + if (jail_get(iov, n, JAIL_AT_DESC) != -1) + _exit(2); + if (errno != EINVAL) + _exit(3); + } + _exit(0); + } + + pid = waitpid(pid, &status, 0); + ATF_REQUIRE_MSG(pid >= 0, "waitpid: %s", strerror(errno)); + ATF_REQUIRE_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "child failed with status %d", status); + + ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno)); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, poll_close_race); ATF_TP_ADD_TC(tp, poll_remove_wakeup); ATF_TP_ADD_TC(tp, poll_close_race_get_desc); + ATF_TP_ADD_TC(tp, curjail_get); + ATF_TP_ADD_TC(tp, self_destruct); + ATF_TP_ADD_TC(tp, at_desc_bad_fd); return (atf_no_error()); }home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a2c2d39.37799.5d17f769>
