git: ac2279ea57b7 - stable/14 - unix/tests: Add a regression test for fd transfer across jails
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 29 Jul 2025 12:49:05 UTC
The branch stable/14 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=ac2279ea57b72d688cf0af5a6fa7f5dbd1d4521b
commit ac2279ea57b72d688cf0af5a6fa7f5dbd1d4521b
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-06-24 20:08:22 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-07-29 12:08:32 +0000
unix/tests: Add a regression test for fd transfer across jails
MFC after: 3 weeks
(cherry picked from commit 5843b8ee02e99527c28f579acfc1f48e10033529)
---
tests/sys/kern/Makefile | 2 +
tests/sys/kern/unix_passfd_test.c | 131 ++++++++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index cb6c3066a03d..ba53e8ffe40d 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -88,6 +88,8 @@ LIBADD.sendfile_helper+= pthread
LIBADD.fdgrowtable_test+= util pthread kvm procstat
LIBADD.sigwait+= rt
LIBADD.ktrace_test+= sysdecode
+LIBADD.unix_passfd_dgram+= jail
+LIBADD.unix_passfd_stream+= jail
NETBSD_ATF_TESTS_C+= lockf_test
NETBSD_ATF_TESTS_C+= mqueue_test
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index d8c0efe5b9ea..dd68020e1bc4 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -28,15 +28,19 @@
#include <sys/cdefs.h>
#include <sys/param.h>
+#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/un.h>
+#include <sys/wait.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <jail.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -946,6 +950,132 @@ ATF_TC_BODY(empty_rights_message, tc)
(void)close(putfd);
}
+ATF_TC_WITH_CLEANUP(cross_jail_dirfd);
+ATF_TC_HEAD(cross_jail_dirfd, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(cross_jail_dirfd, tc)
+{
+ int error, sock[2], jid1, jid2, status;
+ pid_t pid1, pid2;
+
+ domainsocketpair(sock);
+
+ error = mkdir("./a", 0755);
+ ATF_REQUIRE(error == 0);
+ error = mkdir("./b", 0755);
+ ATF_REQUIRE(error == 0);
+ error = mkdir("./c", 0755);
+ ATF_REQUIRE(error == 0);
+ error = mkdir("./a/c", 0755);
+ ATF_REQUIRE(error == 0);
+
+ jid1 = jail_setv(JAIL_CREATE,
+ "name", "passfd_test_cross_jail_dirfd1",
+ "path", "./a",
+ "persist", NULL,
+ NULL);
+ ATF_REQUIRE_MSG(jid1 >= 0, "jail_setv: %s", jail_errmsg);
+
+ jid2 = jail_setv(JAIL_CREATE,
+ "name", "passfd_test_cross_jail_dirfd2",
+ "path", "./b",
+ "persist", NULL,
+ NULL);
+ ATF_REQUIRE_MSG(jid2 >= 0, "jail_setv: %s", jail_errmsg);
+
+ pid1 = fork();
+ ATF_REQUIRE(pid1 >= 0);
+ if (pid1 == 0) {
+ ssize_t len;
+ int dfd, error;
+ char ch;
+
+ error = jail_attach(jid1);
+ if (error != 0)
+ err(1, "jail_attach");
+
+ dfd = open(".", O_RDONLY | O_DIRECTORY);
+ if (dfd < 0)
+ err(1, "open(\".\") in jail %d", jid1);
+
+ ch = 0;
+ len = sendfd_payload(sock[0], dfd, &ch, sizeof(ch));
+ if (len == -1)
+ err(1, "sendmsg");
+
+ _exit(0);
+ }
+
+ pid2 = fork();
+ ATF_REQUIRE(pid2 >= 0);
+ if (pid2 == 0) {
+ int dfd, dfd2, error, fd;
+ char ch;
+
+ error = jail_attach(jid2);
+ if (error != 0)
+ err(1, "jail_attach");
+
+ /* Get a directory from outside the jail root. */
+ recvfd_payload(sock[1], &dfd, &ch, sizeof(ch),
+ CMSG_SPACE(sizeof(int)), 0);
+
+ if ((fcntl(dfd, F_GETFD) & FD_RESOLVE_BENEATH) == 0)
+ errx(1, "dfd does not have FD_RESOLVE_BENEATH set");
+
+ /* Make sure we can't chdir. */
+ error = fchdir(dfd);
+ if (error == 0)
+ errx(1, "fchdir succeeded");
+ if (errno != ENOTCAPABLE)
+ err(1, "fchdir");
+
+ /* Make sure a dotdot access fails. */
+ fd = openat(dfd, "../c", O_RDONLY | O_DIRECTORY);
+ if (fd >= 0)
+ errx(1, "openat(\"../c\") succeeded");
+ if (errno != ENOTCAPABLE)
+ err(1, "openat");
+
+ /* Accesses within the sender's jail root are ok. */
+ fd = openat(dfd, "c", O_RDONLY | O_DIRECTORY);
+ if (fd < 0)
+ err(1, "openat(\"c\")");
+
+ dfd2 = openat(dfd, "", O_EMPTY_PATH | O_RDONLY | O_DIRECTORY);
+ if (dfd2 < 0)
+ err(1, "openat(\"\")");
+ if ((fcntl(dfd2, F_GETFD) & FD_RESOLVE_BENEATH) == 0)
+ errx(1, "dfd2 does not have FD_RESOLVE_BENEATH set");
+
+ _exit(0);
+ }
+
+ error = waitpid(pid1, &status, 0);
+ ATF_REQUIRE(error != -1);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+ error = waitpid(pid2, &status, 0);
+ ATF_REQUIRE(error != -1);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ closesocketpair(sock);
+}
+ATF_TC_CLEANUP(cross_jail_dirfd, tc)
+{
+ int jid;
+
+ jid = jail_getid("passfd_test_cross_jail_dirfd1");
+ if (jid >= 0 && jail_remove(jid) != 0)
+ err(1, "jail_remove");
+ jid = jail_getid("passfd_test_cross_jail_dirfd2");
+ if (jid >= 0 && jail_remove(jid) != 0)
+ err(1, "jail_remove");
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -964,6 +1094,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, truncated_rights);
ATF_TP_ADD_TC(tp, copyout_rights_error);
ATF_TP_ADD_TC(tp, empty_rights_message);
+ ATF_TP_ADD_TC(tp, cross_jail_dirfd);
return (atf_no_error());
}