1 // SPDX-License-Identifier: GPL-2.0-or-later 2 // Copyright (c) 2024 Christian Brauner <brauner@kernel.org> 3 4 #define _GNU_SOURCE 5 #include <fcntl.h> 6 #include <sched.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <sys/stat.h> 10 #include <sys/mount.h> 11 #include <unistd.h> 12 13 #include "../../kselftest_harness.h" 14 15 #define MNT_NS_COUNT 11 16 #define MNT_NS_LAST_INDEX 10 17 18 struct mnt_ns_info { 19 __u32 size; 20 __u32 nr_mounts; 21 __u64 mnt_ns_id; 22 }; 23 24 #define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */ 25 26 /* Get information about namespace. */ 27 #define NS_MNT_GET_INFO _IOR(0xb7, 10, struct mnt_ns_info) 28 /* Get next namespace. */ 29 #define NS_MNT_GET_NEXT _IOR(0xb7, 11, struct mnt_ns_info) 30 /* Get previous namespace. */ 31 #define NS_MNT_GET_PREV _IOR(0xb7, 12, struct mnt_ns_info) 32 33 FIXTURE(iterate_mount_namespaces) { 34 int fd_mnt_ns[MNT_NS_COUNT]; 35 __u64 mnt_ns_id[MNT_NS_COUNT]; 36 }; 37 38 FIXTURE_SETUP(iterate_mount_namespaces) 39 { 40 for (int i = 0; i < MNT_NS_COUNT; i++) 41 self->fd_mnt_ns[i] = -EBADF; 42 43 /* 44 * Creating a new user namespace let's us guarantee that we only see 45 * mount namespaces that we did actually create. 46 */ 47 ASSERT_EQ(unshare(CLONE_NEWUSER), 0); 48 49 for (int i = 0; i < MNT_NS_COUNT; i++) { 50 struct mnt_ns_info info = {}; 51 52 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 53 self->fd_mnt_ns[i] = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC); 54 ASSERT_GE(self->fd_mnt_ns[i], 0); 55 ASSERT_EQ(ioctl(self->fd_mnt_ns[i], NS_MNT_GET_INFO, &info), 0); 56 self->mnt_ns_id[i] = info.mnt_ns_id; 57 } 58 } 59 60 FIXTURE_TEARDOWN(iterate_mount_namespaces) 61 { 62 for (int i = 0; i < MNT_NS_COUNT; i++) { 63 if (self->fd_mnt_ns[i] < 0) 64 continue; 65 ASSERT_EQ(close(self->fd_mnt_ns[i]), 0); 66 } 67 } 68 69 TEST_F(iterate_mount_namespaces, iterate_all_forward) 70 { 71 int fd_mnt_ns_cur, count = 0; 72 73 fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[0], F_DUPFD_CLOEXEC); 74 ASSERT_GE(fd_mnt_ns_cur, 0); 75 76 for (;; count++) { 77 struct mnt_ns_info info = {}; 78 int fd_mnt_ns_next; 79 80 fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info); 81 if (fd_mnt_ns_next < 0 && errno == ENOENT) 82 break; 83 ASSERT_GE(fd_mnt_ns_next, 0); 84 ASSERT_EQ(close(fd_mnt_ns_cur), 0); 85 fd_mnt_ns_cur = fd_mnt_ns_next; 86 } 87 ASSERT_EQ(count, MNT_NS_LAST_INDEX); 88 } 89 90 TEST_F(iterate_mount_namespaces, iterate_all_backwards) 91 { 92 int fd_mnt_ns_cur, count = 0; 93 94 fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[MNT_NS_LAST_INDEX], F_DUPFD_CLOEXEC); 95 ASSERT_GE(fd_mnt_ns_cur, 0); 96 97 for (;; count++) { 98 struct mnt_ns_info info = {}; 99 int fd_mnt_ns_prev; 100 101 fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info); 102 if (fd_mnt_ns_prev < 0 && errno == ENOENT) 103 break; 104 ASSERT_GE(fd_mnt_ns_prev, 0); 105 ASSERT_EQ(close(fd_mnt_ns_cur), 0); 106 fd_mnt_ns_cur = fd_mnt_ns_prev; 107 } 108 ASSERT_EQ(count, MNT_NS_LAST_INDEX); 109 } 110 111 TEST_F(iterate_mount_namespaces, iterate_forward) 112 { 113 int fd_mnt_ns_cur; 114 115 ASSERT_EQ(setns(self->fd_mnt_ns[0], CLONE_NEWNS), 0); 116 117 fd_mnt_ns_cur = self->fd_mnt_ns[0]; 118 for (int i = 1; i < MNT_NS_COUNT; i++) { 119 struct mnt_ns_info info = {}; 120 int fd_mnt_ns_next; 121 122 fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info); 123 ASSERT_GE(fd_mnt_ns_next, 0); 124 ASSERT_EQ(close(fd_mnt_ns_cur), 0); 125 fd_mnt_ns_cur = fd_mnt_ns_next; 126 ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]); 127 } 128 } 129 130 TEST_F(iterate_mount_namespaces, iterate_backward) 131 { 132 int fd_mnt_ns_cur; 133 134 ASSERT_EQ(setns(self->fd_mnt_ns[MNT_NS_LAST_INDEX], CLONE_NEWNS), 0); 135 136 fd_mnt_ns_cur = self->fd_mnt_ns[MNT_NS_LAST_INDEX]; 137 for (int i = MNT_NS_LAST_INDEX - 1; i >= 0; i--) { 138 struct mnt_ns_info info = {}; 139 int fd_mnt_ns_prev; 140 141 fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info); 142 ASSERT_GE(fd_mnt_ns_prev, 0); 143 ASSERT_EQ(close(fd_mnt_ns_cur), 0); 144 fd_mnt_ns_cur = fd_mnt_ns_prev; 145 ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]); 146 } 147 } 148 149 TEST_HARNESS_MAIN 150