Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Jun 2025 21:04:36 GMT
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: 5843b8ee02e9 - main - unix/tests: Add a regression test for fd transfer across jails
Message-ID:  <202506242104.55OL4aUN085282@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=5843b8ee02e99527c28f579acfc1f48e10033529

commit 5843b8ee02e99527c28f579acfc1f48e10033529
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-06-24 20:08:22 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-06-24 21:04:24 +0000

    unix/tests: Add a regression test for fd transfer across jails
    
    MFC after:      3 weeks
---
 tests/sys/kern/Makefile           |   2 +
 tests/sys/kern/unix_passfd_test.c | 134 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+)

diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index 94a75048a31a..8cc7beade3f3 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -96,6 +96,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
 LIBADD.unix_stream+=			pthread
 
 NETBSD_ATF_TESTS_C+=	lockf_test
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index 8c6a976a0e12..95271c04a16b 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -27,15 +27,19 @@
  */
 
 #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>
@@ -1032,6 +1036,135 @@ ATF_TC_BODY(control_creates_records, tc)
 	closesocketpair(fd);
 }
 
+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) {
+		ssize_t len;
+		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. */
+		len = recvfd_payload(sock[1], &dfd, &ch, sizeof(ch),
+		    CMSG_SPACE(sizeof(int)), 0);
+		if (len == -1)
+			err(1, "recvmsg");
+
+		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)
 {
 
@@ -1052,6 +1185,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, copyout_rights_error);
 	ATF_TP_ADD_TC(tp, empty_rights_message);
 	ATF_TP_ADD_TC(tp, control_creates_records);
+	ATF_TP_ADD_TC(tp, cross_jail_dirfd);
 
 	return (atf_no_error());
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506242104.55OL4aUN085282>