aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/kern/jail_lookup_root.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sys/kern/jail_lookup_root.c')
-rw-r--r--tests/sys/kern/jail_lookup_root.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/tests/sys/kern/jail_lookup_root.c b/tests/sys/kern/jail_lookup_root.c
new file mode 100644
index 000000000000..34e89f4aea2b
--- /dev/null
+++ b/tests/sys/kern/jail_lookup_root.c
@@ -0,0 +1,133 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/param.h>
+#include <sys/jail.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <jail.h>
+#include <mntopts.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+static void
+mkdir_checked(const char *dir, mode_t mode)
+{
+ int error;
+
+ error = mkdir(dir, mode);
+ ATF_REQUIRE_MSG(error == 0 || errno == EEXIST,
+ "mkdir %s: %s", dir, strerror(errno));
+}
+
+static void __unused
+mount_nullfs(const char *dir, const char *target)
+{
+ struct iovec *iov;
+ char errmsg[1024];
+ int error, iovlen;
+
+ iov = NULL;
+ iovlen = 0;
+
+ build_iovec(&iov, &iovlen, __DECONST(char *, "fstype"),
+ __DECONST(char *, "nullfs"), (size_t)-1);
+ build_iovec(&iov, &iovlen, __DECONST(char *, "fspath"),
+ __DECONST(char *, target), (size_t)-1);
+ build_iovec(&iov, &iovlen, __DECONST(char *, "from"),
+ __DECONST(char *, dir), (size_t)-1);
+ build_iovec(&iov, &iovlen, __DECONST(char *, "errmsg"),
+ errmsg, sizeof(errmsg));
+
+ errmsg[0] = '\0';
+ error = nmount(iov, iovlen, 0);
+ ATF_REQUIRE_MSG(error == 0, "nmount: %s",
+ errmsg[0] != '\0' ? errmsg : strerror(errno));
+
+ free_iovec(&iov, &iovlen);
+}
+
+ATF_TC_WITH_CLEANUP(jail_root);
+ATF_TC_HEAD(jail_root, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(jail_root, tc)
+{
+ int error, fd, jid;
+
+ mkdir_checked("./root", 0755);
+ mkdir_checked("./root/a", 0755);
+ mkdir_checked("./root/b", 0755);
+ mkdir_checked("./root/a/c", 0755);
+
+ jid = jail_setv(JAIL_CREATE | JAIL_ATTACH,
+ "name", "nullfs_jail_root_test",
+ "allow.mount", "true",
+ "allow.mount.nullfs", "true",
+ "enforce_statfs", "1",
+ "path", "./root",
+ "persist", NULL,
+ NULL);
+ ATF_REQUIRE_MSG(jid >= 0, "jail_setv: %s", jail_errmsg);
+
+ mount_nullfs("/a", "/b");
+
+ error = chdir("/b/c");
+ ATF_REQUIRE(error == 0);
+
+ error = rename("/a/c", "/c");
+ ATF_REQUIRE(error == 0);
+
+ /* Descending to the jail root should be ok. */
+ error = chdir("..");
+ ATF_REQUIRE(error == 0);
+
+ /* Going beyond the root will trigger an error. */
+ error = chdir("..");
+ ATF_REQUIRE_ERRNO(ENOENT, error != 0);
+ fd = open("..", O_RDONLY | O_DIRECTORY);
+ ATF_REQUIRE_ERRNO(ENOENT, fd < 0);
+}
+ATF_TC_CLEANUP(jail_root, tc)
+{
+ struct statfs fs;
+ fsid_t fsid;
+ int error, jid;
+
+ error = statfs("./root/b", &fs);
+ if (error != 0)
+ err(1, "statfs ./b");
+ fsid = fs.f_fsid;
+ error = statfs("./root", &fs);
+ if (error != 0)
+ err(1, "statfs ./root");
+ if (fsid.val[0] != fs.f_fsid.val[0] ||
+ fsid.val[1] != fs.f_fsid.val[1]) {
+ error = unmount("./root/b", 0);
+ if (error != 0)
+ err(1, "unmount ./root/b");
+ }
+
+ jid = jail_getid("nullfs_jail_root_test");
+ if (jid >= 0) {
+ error = jail_remove(jid);
+ if (error != 0)
+ err(1, "jail_remove");
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, jail_root);
+ return (atf_no_error());
+}