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