1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Landlock tests - Common user space base
4 *
5 * Copyright © 2017-2020 Mickaël Salaün <[email protected]>
6 * Copyright © 2019-2020 ANSSI
7 */
8
9 #define _GNU_SOURCE
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <linux/keyctl.h>
13 #include <linux/landlock.h>
14 #include <string.h>
15 #include <sys/prctl.h>
16 #include <sys/socket.h>
17 #include <sys/types.h>
18
19 #include "common.h"
20
21 #ifndef O_PATH
22 #define O_PATH 010000000
23 #endif
24
TEST(inconsistent_attr)25 TEST(inconsistent_attr)
26 {
27 const long page_size = sysconf(_SC_PAGESIZE);
28 char *const buf = malloc(page_size + 1);
29 struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
30
31 ASSERT_NE(NULL, buf);
32
33 /* Checks copy_from_user(). */
34 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0));
35 /* The size if less than sizeof(struct landlock_attr_enforce). */
36 ASSERT_EQ(EINVAL, errno);
37 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0));
38 ASSERT_EQ(EINVAL, errno);
39 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0));
40 ASSERT_EQ(EINVAL, errno);
41
42 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0));
43 /* The size if less than sizeof(struct landlock_attr_enforce). */
44 ASSERT_EQ(EFAULT, errno);
45
46 ASSERT_EQ(-1, landlock_create_ruleset(
47 NULL, sizeof(struct landlock_ruleset_attr), 0));
48 ASSERT_EQ(EFAULT, errno);
49
50 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
51 ASSERT_EQ(E2BIG, errno);
52
53 /* Checks minimal valid attribute size. */
54 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0));
55 ASSERT_EQ(ENOMSG, errno);
56 ASSERT_EQ(-1, landlock_create_ruleset(
57 ruleset_attr,
58 sizeof(struct landlock_ruleset_attr), 0));
59 ASSERT_EQ(ENOMSG, errno);
60 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
61 ASSERT_EQ(ENOMSG, errno);
62
63 /* Checks non-zero value. */
64 buf[page_size - 2] = '.';
65 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
66 ASSERT_EQ(E2BIG, errno);
67
68 ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
69 ASSERT_EQ(E2BIG, errno);
70
71 free(buf);
72 }
73
TEST(abi_version)74 TEST(abi_version)
75 {
76 const struct landlock_ruleset_attr ruleset_attr = {
77 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
78 };
79 ASSERT_EQ(6, landlock_create_ruleset(NULL, 0,
80 LANDLOCK_CREATE_RULESET_VERSION));
81
82 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
83 LANDLOCK_CREATE_RULESET_VERSION));
84 ASSERT_EQ(EINVAL, errno);
85
86 ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
87 LANDLOCK_CREATE_RULESET_VERSION));
88 ASSERT_EQ(EINVAL, errno);
89
90 ASSERT_EQ(-1,
91 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
92 LANDLOCK_CREATE_RULESET_VERSION));
93 ASSERT_EQ(EINVAL, errno);
94
95 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
96 LANDLOCK_CREATE_RULESET_VERSION |
97 1 << 31));
98 ASSERT_EQ(EINVAL, errno);
99 }
100
101 /*
102 * Old source trees might not have the set of Kselftest fixes related to kernel
103 * UAPI headers.
104 */
105 #ifndef LANDLOCK_CREATE_RULESET_ERRATA
106 #define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
107 #endif
108
TEST(errata)109 TEST(errata)
110 {
111 const struct landlock_ruleset_attr ruleset_attr = {
112 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
113 };
114 int errata;
115
116 errata = landlock_create_ruleset(NULL, 0,
117 LANDLOCK_CREATE_RULESET_ERRATA);
118 /* The errata bitmask will not be backported to tests. */
119 ASSERT_LE(0, errata);
120 TH_LOG("errata: 0x%x", errata);
121
122 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
123 LANDLOCK_CREATE_RULESET_ERRATA));
124 ASSERT_EQ(EINVAL, errno);
125
126 ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
127 LANDLOCK_CREATE_RULESET_ERRATA));
128 ASSERT_EQ(EINVAL, errno);
129
130 ASSERT_EQ(-1,
131 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
132 LANDLOCK_CREATE_RULESET_ERRATA));
133 ASSERT_EQ(EINVAL, errno);
134
135 ASSERT_EQ(-1, landlock_create_ruleset(
136 NULL, 0,
137 LANDLOCK_CREATE_RULESET_VERSION |
138 LANDLOCK_CREATE_RULESET_ERRATA));
139 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
140 LANDLOCK_CREATE_RULESET_ERRATA |
141 1 << 31));
142 ASSERT_EQ(EINVAL, errno);
143 }
144
145 /* Tests ordering of syscall argument checks. */
TEST(create_ruleset_checks_ordering)146 TEST(create_ruleset_checks_ordering)
147 {
148 const int last_flag = LANDLOCK_CREATE_RULESET_ERRATA;
149 const int invalid_flag = last_flag << 1;
150 int ruleset_fd;
151 const struct landlock_ruleset_attr ruleset_attr = {
152 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
153 };
154
155 /* Checks priority for invalid flags. */
156 ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag));
157 ASSERT_EQ(EINVAL, errno);
158
159 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag));
160 ASSERT_EQ(EINVAL, errno);
161
162 ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
163 invalid_flag));
164 ASSERT_EQ(EINVAL, errno);
165
166 ASSERT_EQ(-1,
167 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
168 invalid_flag));
169 ASSERT_EQ(EINVAL, errno);
170
171 /* Checks too big ruleset_attr size. */
172 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0));
173 ASSERT_EQ(E2BIG, errno);
174
175 /* Checks too small ruleset_attr size. */
176 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0));
177 ASSERT_EQ(EINVAL, errno);
178 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0));
179 ASSERT_EQ(EINVAL, errno);
180
181 /* Checks valid call. */
182 ruleset_fd =
183 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
184 ASSERT_LE(0, ruleset_fd);
185 ASSERT_EQ(0, close(ruleset_fd));
186 }
187
188 /* Tests ordering of syscall argument checks. */
TEST(add_rule_checks_ordering)189 TEST(add_rule_checks_ordering)
190 {
191 const struct landlock_ruleset_attr ruleset_attr = {
192 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
193 };
194 struct landlock_path_beneath_attr path_beneath_attr = {
195 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
196 .parent_fd = -1,
197 };
198 const int ruleset_fd =
199 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
200
201 ASSERT_LE(0, ruleset_fd);
202
203 /* Checks invalid flags. */
204 ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
205 ASSERT_EQ(EINVAL, errno);
206
207 /* Checks invalid ruleset FD. */
208 ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0));
209 ASSERT_EQ(EBADF, errno);
210
211 /* Checks invalid rule type. */
212 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0));
213 ASSERT_EQ(EINVAL, errno);
214
215 /* Checks invalid rule attr. */
216 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
217 NULL, 0));
218 ASSERT_EQ(EFAULT, errno);
219
220 /* Checks invalid path_beneath.parent_fd. */
221 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
222 &path_beneath_attr, 0));
223 ASSERT_EQ(EBADF, errno);
224
225 /* Checks valid call. */
226 path_beneath_attr.parent_fd =
227 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
228 ASSERT_LE(0, path_beneath_attr.parent_fd);
229 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
230 &path_beneath_attr, 0));
231 ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
232 ASSERT_EQ(0, close(ruleset_fd));
233 }
234
235 /* Tests ordering of syscall argument and permission checks. */
TEST(restrict_self_checks_ordering)236 TEST(restrict_self_checks_ordering)
237 {
238 const struct landlock_ruleset_attr ruleset_attr = {
239 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
240 };
241 struct landlock_path_beneath_attr path_beneath_attr = {
242 .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
243 .parent_fd = -1,
244 };
245 const int ruleset_fd =
246 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
247
248 ASSERT_LE(0, ruleset_fd);
249 path_beneath_attr.parent_fd =
250 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
251 ASSERT_LE(0, path_beneath_attr.parent_fd);
252 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
253 &path_beneath_attr, 0));
254 ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
255
256 /* Checks unprivileged enforcement without no_new_privs. */
257 drop_caps(_metadata);
258 ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
259 ASSERT_EQ(EPERM, errno);
260 ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
261 ASSERT_EQ(EPERM, errno);
262 ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
263 ASSERT_EQ(EPERM, errno);
264
265 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
266
267 /* Checks invalid flags. */
268 ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
269 ASSERT_EQ(EINVAL, errno);
270
271 /* Checks invalid ruleset FD. */
272 ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
273 ASSERT_EQ(EBADF, errno);
274
275 /* Checks valid call. */
276 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
277 ASSERT_EQ(0, close(ruleset_fd));
278 }
279
TEST(ruleset_fd_io)280 TEST(ruleset_fd_io)
281 {
282 struct landlock_ruleset_attr ruleset_attr = {
283 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
284 };
285 int ruleset_fd;
286 char buf;
287
288 drop_caps(_metadata);
289 ruleset_fd =
290 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
291 ASSERT_LE(0, ruleset_fd);
292
293 ASSERT_EQ(-1, write(ruleset_fd, ".", 1));
294 ASSERT_EQ(EINVAL, errno);
295 ASSERT_EQ(-1, read(ruleset_fd, &buf, 1));
296 ASSERT_EQ(EINVAL, errno);
297
298 ASSERT_EQ(0, close(ruleset_fd));
299 }
300
301 /* Tests enforcement of a ruleset FD transferred through a UNIX socket. */
TEST(ruleset_fd_transfer)302 TEST(ruleset_fd_transfer)
303 {
304 struct landlock_ruleset_attr ruleset_attr = {
305 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
306 };
307 struct landlock_path_beneath_attr path_beneath_attr = {
308 .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
309 };
310 int ruleset_fd_tx, dir_fd;
311 int socket_fds[2];
312 pid_t child;
313 int status;
314
315 drop_caps(_metadata);
316
317 /* Creates a test ruleset with a simple rule. */
318 ruleset_fd_tx =
319 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
320 ASSERT_LE(0, ruleset_fd_tx);
321 path_beneath_attr.parent_fd =
322 open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
323 ASSERT_LE(0, path_beneath_attr.parent_fd);
324 ASSERT_EQ(0,
325 landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH,
326 &path_beneath_attr, 0));
327 ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
328
329 /* Sends the ruleset FD over a socketpair and then close it. */
330 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
331 socket_fds));
332 ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx));
333 ASSERT_EQ(0, close(socket_fds[0]));
334 ASSERT_EQ(0, close(ruleset_fd_tx));
335
336 child = fork();
337 ASSERT_LE(0, child);
338 if (child == 0) {
339 const int ruleset_fd_rx = recv_fd(socket_fds[1]);
340
341 ASSERT_LE(0, ruleset_fd_rx);
342 ASSERT_EQ(0, close(socket_fds[1]));
343
344 /* Enforces the received ruleset on the child. */
345 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
346 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0));
347 ASSERT_EQ(0, close(ruleset_fd_rx));
348
349 /* Checks that the ruleset enforcement. */
350 ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
351 ASSERT_EQ(EACCES, errno);
352 dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
353 ASSERT_LE(0, dir_fd);
354 ASSERT_EQ(0, close(dir_fd));
355 _exit(_metadata->exit_code);
356 return;
357 }
358
359 ASSERT_EQ(0, close(socket_fds[1]));
360
361 /* Checks that the parent is unrestricted. */
362 dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
363 ASSERT_LE(0, dir_fd);
364 ASSERT_EQ(0, close(dir_fd));
365 dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
366 ASSERT_LE(0, dir_fd);
367 ASSERT_EQ(0, close(dir_fd));
368
369 ASSERT_EQ(child, waitpid(child, &status, 0));
370 ASSERT_EQ(1, WIFEXITED(status));
371 ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
372 }
373
TEST(cred_transfer)374 TEST(cred_transfer)
375 {
376 struct landlock_ruleset_attr ruleset_attr = {
377 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
378 };
379 int ruleset_fd, dir_fd;
380 pid_t child;
381 int status;
382
383 drop_caps(_metadata);
384
385 dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
386 EXPECT_LE(0, dir_fd);
387 EXPECT_EQ(0, close(dir_fd));
388
389 /* Denies opening directories. */
390 ruleset_fd =
391 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
392 ASSERT_LE(0, ruleset_fd);
393 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
394 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
395 EXPECT_EQ(0, close(ruleset_fd));
396
397 /* Checks ruleset enforcement. */
398 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
399 EXPECT_EQ(EACCES, errno);
400
401 /* Needed for KEYCTL_SESSION_TO_PARENT permission checks */
402 EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL, 0,
403 0, 0))
404 {
405 TH_LOG("Failed to join session keyring: %s", strerror(errno));
406 }
407
408 child = fork();
409 ASSERT_LE(0, child);
410 if (child == 0) {
411 /* Checks ruleset enforcement. */
412 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
413 EXPECT_EQ(EACCES, errno);
414
415 /*
416 * KEYCTL_SESSION_TO_PARENT is a no-op unless we have a
417 * different session keyring in the child, so make that happen.
418 */
419 EXPECT_NE(-1, syscall(__NR_keyctl, KEYCTL_JOIN_SESSION_KEYRING,
420 NULL, 0, 0, 0));
421
422 /*
423 * KEYCTL_SESSION_TO_PARENT installs credentials on the parent
424 * that never go through the cred_prepare hook, this path uses
425 * cred_transfer instead.
426 */
427 EXPECT_EQ(0, syscall(__NR_keyctl, KEYCTL_SESSION_TO_PARENT, 0,
428 0, 0, 0));
429
430 /* Re-checks ruleset enforcement. */
431 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
432 EXPECT_EQ(EACCES, errno);
433
434 _exit(_metadata->exit_code);
435 return;
436 }
437
438 EXPECT_EQ(child, waitpid(child, &status, 0));
439 EXPECT_EQ(1, WIFEXITED(status));
440 EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
441
442 /* Re-checks ruleset enforcement. */
443 EXPECT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
444 EXPECT_EQ(EACCES, errno);
445 }
446
447 TEST_HARNESS_MAIN
448