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
FIXTURE(iterate_mount_namespaces)33 FIXTURE(iterate_mount_namespaces) {
34 int fd_mnt_ns[MNT_NS_COUNT];
35 __u64 mnt_ns_id[MNT_NS_COUNT];
36 };
37
FIXTURE_SETUP(iterate_mount_namespaces)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
FIXTURE_TEARDOWN(iterate_mount_namespaces)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
TEST_F(iterate_mount_namespaces,iterate_all_forward)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
TEST_F(iterate_mount_namespaces,iterate_all_backwards)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
TEST_F(iterate_mount_namespaces,iterate_forward)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
TEST_F(iterate_mount_namespaces,iterate_backward)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