projects/linux·blob master · refs

299 lines · 6.9 KiB

1// SPDX-License-Identifier: GPL-2.0
2#define _GNU_SOURCE
3#include <errno.h>
4#include <fcntl.h>
5#include <sched.h>
6#include <stdio.h>
7#include <string.h>
8#include <sys/wait.h>
9#include <unistd.h>
10#include "../kselftest_harness.h"
11
12/*
13 * The fields of a uid_map/gid_map line are stored in u32. Values that
14 * do not fit, and negative values, must be rejected with EINVAL instead
15 * of being silently truncated, and in-range values must still be
16 * accepted.
17 */
18
19static int write_file(const char *path, const char *buf)
20{
21 ssize_t len = strlen(buf);
22 ssize_t ret;
23 int fd;
24
25 fd = open(path, O_WRONLY | O_CLOEXEC);
26 if (fd < 0)
27 return -errno;
28 ret = write(fd, buf, len);
29 if (ret < 0)
30 ret = -errno;
31 close(fd);
32 if (ret < 0)
33 return ret;
34 return ret == len ? 0 : -EIO;
35}
36
37static ssize_t read_file(const char *path, char *buf, size_t size)
38{
39 ssize_t ret;
40 int fd;
41
42 fd = open(path, O_RDONLY | O_CLOEXEC);
43 if (fd < 0)
44 return -errno;
45 ret = read(fd, buf, size - 1);
46 if (ret < 0)
47 ret = -errno;
48 else
49 buf[ret] = '\0';
50 close(fd);
51 return ret;
52}
53
54/* Enter a fresh user namespace, remembering the outer ids. */
55static int enter_userns(uid_t *uid, gid_t *gid)
56{
57 *uid = geteuid();
58 *gid = getegid();
59 if (unshare(CLONE_NEWUSER) < 0)
60 return -errno;
61 /* Required before an unprivileged gid_map write. */
62 return write_file("/proc/self/setgroups", "deny");
63}
64
65static void expect_rejected(struct __test_metadata *_metadata,
66 const char *path, const char *line)
67{
68 char buf[256];
69
70 TH_LOG("writing \"%s\" to %s", line, path);
71 EXPECT_EQ(write_file(path, line), -EINVAL);
72 /* Nothing may have been installed. */
73 EXPECT_EQ(read_file(path, buf, sizeof(buf)), 0) {
74 TH_LOG("installed: %s", buf);
75 }
76}
77
78static void expect_accepted(struct __test_metadata *_metadata,
79 const char *path, const char *line,
80 unsigned int first, unsigned int lower_first,
81 unsigned int count)
82{
83 unsigned int f, l, c;
84 char buf[256];
85
86 TH_LOG("writing \"%s\" to %s", line, path);
87 ASSERT_EQ(write_file(path, line), 0);
88
89 ASSERT_GT(read_file(path, buf, sizeof(buf)), 0);
90 ASSERT_EQ(sscanf(buf, "%u %u %u", &f, &l, &c), 3);
91 EXPECT_EQ(f, first);
92 EXPECT_EQ(l, lower_first);
93 EXPECT_EQ(c, count);
94 /* Exactly one extent. */
95 EXPECT_EQ(strchr(buf, '\n'), buf + strlen(buf) - 1);
96}
97
98TEST(uid_map_first_above_u32)
99{
100 char line[64];
101 uid_t uid;
102 gid_t gid;
103 int ret;
104
105 ret = enter_userns(&uid, &gid);
106 if (ret)
107 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
108 snprintf(line, sizeof(line), "4294967301 %u 1", uid);
109 expect_rejected(_metadata, "/proc/self/uid_map", line);
110}
111
112TEST(uid_map_lower_first_above_u32)
113{
114 char line[64];
115 uid_t uid;
116 gid_t gid;
117 int ret;
118
119 ret = enter_userns(&uid, &gid);
120 if (ret)
121 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
122 snprintf(line, sizeof(line), "0 %llu 1", (1ULL << 32) + uid);
123 expect_rejected(_metadata, "/proc/self/uid_map", line);
124}
125
126TEST(uid_map_count_above_u32)
127{
128 char line[64];
129 uid_t uid;
130 gid_t gid;
131 int ret;
132
133 ret = enter_userns(&uid, &gid);
134 if (ret)
135 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
136 snprintf(line, sizeof(line), "0 %u 4294967297", uid);
137 expect_rejected(_metadata, "/proc/self/uid_map", line);
138}
139
140TEST(gid_map_first_above_u32)
141{
142 char line[64];
143 uid_t uid;
144 gid_t gid;
145 int ret;
146
147 ret = enter_userns(&uid, &gid);
148 if (ret)
149 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
150 snprintf(line, sizeof(line), "4294967301 %u 1", gid);
151 expect_rejected(_metadata, "/proc/self/gid_map", line);
152}
153
154TEST(uid_map_first_negative)
155{
156 char line[64];
157 uid_t uid;
158 gid_t gid;
159 int ret;
160
161 ret = enter_userns(&uid, &gid);
162 if (ret)
163 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
164 snprintf(line, sizeof(line), "-1 %u 1", uid);
165 expect_rejected(_metadata, "/proc/self/uid_map", line);
166}
167
168TEST(uid_map_lower_first_negative)
169{
170 uid_t uid;
171 gid_t gid;
172 int ret;
173
174 ret = enter_userns(&uid, &gid);
175 if (ret)
176 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
177 expect_rejected(_metadata, "/proc/self/uid_map", "0 -1 1");
178}
179
180TEST(uid_map_count_negative)
181{
182 char line[64];
183 uid_t uid;
184 gid_t gid;
185 int ret;
186
187 ret = enter_userns(&uid, &gid);
188 if (ret)
189 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
190 snprintf(line, sizeof(line), "0 %u -1", uid);
191 expect_rejected(_metadata, "/proc/self/uid_map", line);
192}
193
194TEST(uid_map_in_range)
195{
196 char line[64];
197 uid_t uid;
198 gid_t gid;
199 int ret;
200
201 ret = enter_userns(&uid, &gid);
202 if (ret)
203 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
204 snprintf(line, sizeof(line), "5 %u 1", uid);
205 expect_accepted(_metadata, "/proc/self/uid_map", line, 5, uid, 1);
206}
207
208TEST(uid_map_zero)
209{
210 char line[64];
211 uid_t uid;
212 gid_t gid;
213 int ret;
214
215 ret = enter_userns(&uid, &gid);
216 if (ret)
217 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
218 snprintf(line, sizeof(line), "0 %u 1", uid);
219 expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1);
220}
221
222/* 4294967295 is (u32)-1, which map_write() refuses as a starting id. */
223TEST(uid_map_largest_first)
224{
225 char line[64];
226 uid_t uid;
227 gid_t gid;
228 int ret;
229
230 ret = enter_userns(&uid, &gid);
231 if (ret)
232 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
233 snprintf(line, sizeof(line), "4294967294 %u 1", uid);
234 expect_accepted(_metadata, "/proc/self/uid_map", line,
235 4294967294U, uid, 1);
236}
237
238TEST(uid_map_extra_spaces)
239{
240 char line[64];
241 uid_t uid;
242 gid_t gid;
243 int ret;
244
245 ret = enter_userns(&uid, &gid);
246 if (ret)
247 SKIP(return, "cannot set up user namespace: %s", strerror(-ret));
248 snprintf(line, sizeof(line), "0 %u 1", uid);
249 expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1);
250}
251
252/*
253 * An unprivileged writer may only map a single id, so the largest count
254 * needs a privileged parent writing the map of a child namespace. With
255 * first and lower_first 0, the no-wrap rule allows up to 4294967295.
256 */
257TEST(uid_map_largest_count)
258{
259 unsigned int first, lower_first, count;
260 int to_child[2], from_child[2];
261 char path[64], buf[256];
262 pid_t pid;
263 char c;
264
265 if (geteuid() != 0)
266 SKIP(return, "needs root in the initial user namespace");
267 ASSERT_GT(read_file("/proc/self/uid_map", buf, sizeof(buf)), 0);
268 ASSERT_EQ(sscanf(buf, "%u %u %u", &first, &lower_first, &count), 3);
269 if (first != 0 || lower_first != 0 || count != 4294967295U)
270 SKIP(return, "not in the initial user namespace");
271
272 ASSERT_EQ(pipe(to_child), 0);
273 ASSERT_EQ(pipe(from_child), 0);
274 pid = fork();
275 ASSERT_GE(pid, 0);
276 if (pid == 0) {
277 close(to_child[1]);
278 close(from_child[0]);
279 c = unshare(CLONE_NEWUSER) ? 'F' : 'K';
280 if (write(from_child[1], &c, 1) != 1)
281 _exit(1);
282 /* Stay alive until the parent is done with our uid_map. */
283 if (read(to_child[0], &c, 1) < 0)
284 _exit(1);
285 _exit(0);
286 }
287 close(to_child[0]);
288 close(from_child[1]);
289
290 ASSERT_EQ(read(from_child[0], &c, 1), 1);
291 ASSERT_EQ(c, 'K');
292 snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
293 expect_accepted(_metadata, path, "0 0 4294967295", 0, 0, 4294967295U);
294
295 close(to_child[1]);
296 EXPECT_EQ(waitpid(pid, NULL, 0), pid);
297}
298
299TEST_HARNESS_MAIN