]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/namespaces: fourth active reference count tests
authorChristian Brauner <brauner@kernel.org>
Wed, 29 Oct 2025 12:20:39 +0000 (13:20 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 3 Nov 2025 16:41:19 +0000 (17:41 +0100)
Test user namespace active ref tracking via credential lifecycle.

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-26-2e6f823ebdc0@kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
tools/testing/selftests/namespaces/ns_active_ref_test.c

index c2e34de7a3a9b0db396ee2e69473fdd93cc7d150..396066e641da1463b6bbfd65a9b9c7c86a55572b 100644 (file)
@@ -276,4 +276,94 @@ TEST(ns_active_with_multiple_processes)
        ASSERT_TRUE(WIFEXITED(status));
 }
 
+/*
+ * Test user namespace active ref tracking via credential lifecycle
+ */
+TEST(userns_active_ref_lifecycle)
+{
+       struct file_handle *handle;
+       int mount_id;
+       int ret;
+       int fd;
+       int pipefd[2];
+       pid_t pid;
+       int status;
+       char buf[sizeof(*handle) + MAX_HANDLE_SZ];
+
+       ASSERT_EQ(pipe(pipefd), 0);
+
+       pid = fork();
+       ASSERT_GE(pid, 0);
+
+       if (pid == 0) {
+               /* Child process */
+               close(pipefd[0]);
+
+               /* Create new user namespace */
+               ret = unshare(CLONE_NEWUSER);
+               if (ret < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               /* Set up uid/gid mappings */
+               int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
+               int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
+               int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
+
+               if (uid_map_fd >= 0 && gid_map_fd >= 0 && setgroups_fd >= 0) {
+                       write(setgroups_fd, "deny", 4);
+                       close(setgroups_fd);
+
+                       char mapping[64];
+                       snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
+                       write(uid_map_fd, mapping, strlen(mapping));
+                       close(uid_map_fd);
+
+                       snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
+                       write(gid_map_fd, mapping, strlen(mapping));
+                       close(gid_map_fd);
+               }
+
+               /* Get file handle */
+               fd = open("/proc/self/ns/user", O_RDONLY);
+               if (fd < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               handle = (struct file_handle *)buf;
+               handle->handle_bytes = MAX_HANDLE_SZ;
+               ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
+               close(fd);
+
+               if (ret < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               /* Send handle to parent */
+               write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
+               close(pipefd[1]);
+               exit(0);
+       }
+
+       /* Parent */
+       close(pipefd[1]);
+       ret = read(pipefd[0], buf, sizeof(buf));
+       close(pipefd[0]);
+
+       waitpid(pid, &status, 0);
+       ASSERT_TRUE(WIFEXITED(status));
+       ASSERT_EQ(WEXITSTATUS(status), 0);
+
+       ASSERT_GT(ret, 0);
+       handle = (struct file_handle *)buf;
+
+       /* Namespace should be inactive after all tasks exit */
+       fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
+       ASSERT_LT(fd, 0);
+       ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
+}
+
 TEST_HARNESS_MAIN