1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Landlock tests - Filesystem
4 *
5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6 * Copyright © 2020 ANSSI
7 * Copyright © 2020-2021 Microsoft Corporation
8 */
9
10 #define _GNU_SOURCE
11 #include <fcntl.h>
12 #include <linux/landlock.h>
13 #include <sched.h>
14 #include <string.h>
15 #include <sys/capability.h>
16 #include <sys/mount.h>
17 #include <sys/prctl.h>
18 #include <sys/sendfile.h>
19 #include <sys/stat.h>
20 #include <sys/sysmacros.h>
21 #include <unistd.h>
22
23 #include "common.h"
24
25 #define TMP_DIR "tmp"
26 #define BINARY_PATH "./true"
27
28 /* Paths (sibling number and depth) */
29 static const char dir_s1d1[] = TMP_DIR "/s1d1";
30 static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
31 static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
32 static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
33 static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
34 static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
35 static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
36 static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
37 static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
38
39 static const char dir_s2d1[] = TMP_DIR "/s2d1";
40 static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
41 static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
42 static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
43 static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
44 static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
45 static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
46
47 static const char dir_s3d1[] = TMP_DIR "/s3d1";
48 /* dir_s3d2 is a mount point. */
49 static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
50 static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
51
52 /*
53 * layout1 hierarchy:
54 *
55 * tmp
56 * ├── s1d1
57 * │ ├── f1
58 * │ ├── f2
59 * │ └── s1d2
60 * │ ├── f1
61 * │ ├── f2
62 * │ └── s1d3
63 * │ ├── f1
64 * │ └── f2
65 * ├── s2d1
66 * │ ├── f1
67 * │ └── s2d2
68 * │ ├── f1
69 * │ └── s2d3
70 * │ ├── f1
71 * │ └── f2
72 * └── s3d1
73 * └── s3d2
74 * └── s3d3
75 */
76
mkdir_parents(struct __test_metadata * const _metadata,const char * const path)77 static void mkdir_parents(struct __test_metadata *const _metadata,
78 const char *const path)
79 {
80 char *walker;
81 const char *parent;
82 int i, err;
83
84 ASSERT_NE(path[0], '\0');
85 walker = strdup(path);
86 ASSERT_NE(NULL, walker);
87 parent = walker;
88 for (i = 1; walker[i]; i++) {
89 if (walker[i] != '/')
90 continue;
91 walker[i] = '\0';
92 err = mkdir(parent, 0700);
93 ASSERT_FALSE(err && errno != EEXIST) {
94 TH_LOG("Failed to create directory \"%s\": %s",
95 parent, strerror(errno));
96 }
97 walker[i] = '/';
98 }
99 free(walker);
100 }
101
create_directory(struct __test_metadata * const _metadata,const char * const path)102 static void create_directory(struct __test_metadata *const _metadata,
103 const char *const path)
104 {
105 mkdir_parents(_metadata, path);
106 ASSERT_EQ(0, mkdir(path, 0700)) {
107 TH_LOG("Failed to create directory \"%s\": %s", path,
108 strerror(errno));
109 }
110 }
111
create_file(struct __test_metadata * const _metadata,const char * const path)112 static void create_file(struct __test_metadata *const _metadata,
113 const char *const path)
114 {
115 mkdir_parents(_metadata, path);
116 ASSERT_EQ(0, mknod(path, S_IFREG | 0700, 0)) {
117 TH_LOG("Failed to create file \"%s\": %s", path,
118 strerror(errno));
119 }
120 }
121
remove_path(const char * const path)122 static int remove_path(const char *const path)
123 {
124 char *walker;
125 int i, ret, err = 0;
126
127 walker = strdup(path);
128 if (!walker) {
129 err = ENOMEM;
130 goto out;
131 }
132 if (unlink(path) && rmdir(path)) {
133 if (errno != ENOENT)
134 err = errno;
135 goto out;
136 }
137 for (i = strlen(walker); i > 0; i--) {
138 if (walker[i] != '/')
139 continue;
140 walker[i] = '\0';
141 ret = rmdir(walker);
142 if (ret) {
143 if (errno != ENOTEMPTY && errno != EBUSY)
144 err = errno;
145 goto out;
146 }
147 if (strcmp(walker, TMP_DIR) == 0)
148 goto out;
149 }
150
151 out:
152 free(walker);
153 return err;
154 }
155
prepare_layout(struct __test_metadata * const _metadata)156 static void prepare_layout(struct __test_metadata *const _metadata)
157 {
158 disable_caps(_metadata);
159 umask(0077);
160 create_directory(_metadata, TMP_DIR);
161
162 /*
163 * Do not pollute the rest of the system: creates a private mount point
164 * for tests relying on pivot_root(2) and move_mount(2).
165 */
166 set_cap(_metadata, CAP_SYS_ADMIN);
167 ASSERT_EQ(0, unshare(CLONE_NEWNS));
168 ASSERT_EQ(0, mount("tmp", TMP_DIR, "tmpfs", 0, "size=4m,mode=700"));
169 ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL));
170 clear_cap(_metadata, CAP_SYS_ADMIN);
171 }
172
cleanup_layout(struct __test_metadata * const _metadata)173 static void cleanup_layout(struct __test_metadata *const _metadata)
174 {
175 set_cap(_metadata, CAP_SYS_ADMIN);
176 EXPECT_EQ(0, umount(TMP_DIR));
177 clear_cap(_metadata, CAP_SYS_ADMIN);
178 EXPECT_EQ(0, remove_path(TMP_DIR));
179 }
180
create_layout1(struct __test_metadata * const _metadata)181 static void create_layout1(struct __test_metadata *const _metadata)
182 {
183 create_file(_metadata, file1_s1d1);
184 create_file(_metadata, file1_s1d2);
185 create_file(_metadata, file1_s1d3);
186 create_file(_metadata, file2_s1d1);
187 create_file(_metadata, file2_s1d2);
188 create_file(_metadata, file2_s1d3);
189
190 create_file(_metadata, file1_s2d1);
191 create_file(_metadata, file1_s2d2);
192 create_file(_metadata, file1_s2d3);
193 create_file(_metadata, file2_s2d3);
194
195 create_directory(_metadata, dir_s3d2);
196 set_cap(_metadata, CAP_SYS_ADMIN);
197 ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700"));
198 clear_cap(_metadata, CAP_SYS_ADMIN);
199
200 ASSERT_EQ(0, mkdir(dir_s3d3, 0700));
201 }
202
remove_layout1(struct __test_metadata * const _metadata)203 static void remove_layout1(struct __test_metadata *const _metadata)
204 {
205 EXPECT_EQ(0, remove_path(file2_s1d3));
206 EXPECT_EQ(0, remove_path(file2_s1d2));
207 EXPECT_EQ(0, remove_path(file2_s1d1));
208 EXPECT_EQ(0, remove_path(file1_s1d3));
209 EXPECT_EQ(0, remove_path(file1_s1d2));
210 EXPECT_EQ(0, remove_path(file1_s1d1));
211
212 EXPECT_EQ(0, remove_path(file2_s2d3));
213 EXPECT_EQ(0, remove_path(file1_s2d3));
214 EXPECT_EQ(0, remove_path(file1_s2d2));
215 EXPECT_EQ(0, remove_path(file1_s2d1));
216
217 EXPECT_EQ(0, remove_path(dir_s3d3));
218 set_cap(_metadata, CAP_SYS_ADMIN);
219 umount(dir_s3d2);
220 clear_cap(_metadata, CAP_SYS_ADMIN);
221 EXPECT_EQ(0, remove_path(dir_s3d2));
222 }
223
FIXTURE(layout1)224 FIXTURE(layout1) {
225 };
226
FIXTURE_SETUP(layout1)227 FIXTURE_SETUP(layout1)
228 {
229 prepare_layout(_metadata);
230
231 create_layout1(_metadata);
232 }
233
FIXTURE_TEARDOWN(layout1)234 FIXTURE_TEARDOWN(layout1)
235 {
236 remove_layout1(_metadata);
237
238 cleanup_layout(_metadata);
239 }
240
241 /*
242 * This helper enables to use the ASSERT_* macros and print the line number
243 * pointing to the test caller.
244 */
test_open_rel(const int dirfd,const char * const path,const int flags)245 static int test_open_rel(const int dirfd, const char *const path, const int flags)
246 {
247 int fd;
248
249 /* Works with file and directories. */
250 fd = openat(dirfd, path, flags | O_CLOEXEC);
251 if (fd < 0)
252 return errno;
253 /*
254 * Mixing error codes from close(2) and open(2) should not lead to any
255 * (access type) confusion for this test.
256 */
257 if (close(fd) != 0)
258 return errno;
259 return 0;
260 }
261
test_open(const char * const path,const int flags)262 static int test_open(const char *const path, const int flags)
263 {
264 return test_open_rel(AT_FDCWD, path, flags);
265 }
266
TEST_F_FORK(layout1,no_restriction)267 TEST_F_FORK(layout1, no_restriction)
268 {
269 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
270 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
271 ASSERT_EQ(0, test_open(file2_s1d1, O_RDONLY));
272 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
273 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
274 ASSERT_EQ(0, test_open(file2_s1d2, O_RDONLY));
275 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
276 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
277
278 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
279 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
280 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
281 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
282 ASSERT_EQ(0, test_open(dir_s2d3, O_RDONLY));
283 ASSERT_EQ(0, test_open(file1_s2d3, O_RDONLY));
284
285 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
286 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
287 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
288 }
289
TEST_F_FORK(layout1,inval)290 TEST_F_FORK(layout1, inval)
291 {
292 struct landlock_path_beneath_attr path_beneath = {
293 .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
294 LANDLOCK_ACCESS_FS_WRITE_FILE,
295 .parent_fd = -1,
296 };
297 struct landlock_ruleset_attr ruleset_attr = {
298 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
299 LANDLOCK_ACCESS_FS_WRITE_FILE,
300 };
301 int ruleset_fd;
302
303 path_beneath.parent_fd = open(dir_s1d2, O_PATH | O_DIRECTORY |
304 O_CLOEXEC);
305 ASSERT_LE(0, path_beneath.parent_fd);
306
307 ruleset_fd = open(dir_s1d1, O_PATH | O_DIRECTORY | O_CLOEXEC);
308 ASSERT_LE(0, ruleset_fd);
309 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
310 &path_beneath, 0));
311 /* Returns EBADF because ruleset_fd is not a landlock-ruleset FD. */
312 ASSERT_EQ(EBADF, errno);
313 ASSERT_EQ(0, close(ruleset_fd));
314
315 ruleset_fd = open(dir_s1d1, O_DIRECTORY | O_CLOEXEC);
316 ASSERT_LE(0, ruleset_fd);
317 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
318 &path_beneath, 0));
319 /* Returns EBADFD because ruleset_fd is not a valid ruleset. */
320 ASSERT_EQ(EBADFD, errno);
321 ASSERT_EQ(0, close(ruleset_fd));
322
323 /* Gets a real ruleset. */
324 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
325 sizeof(ruleset_attr), 0);
326 ASSERT_LE(0, ruleset_fd);
327 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
328 &path_beneath, 0));
329 ASSERT_EQ(0, close(path_beneath.parent_fd));
330
331 /* Tests without O_PATH. */
332 path_beneath.parent_fd = open(dir_s1d2, O_DIRECTORY | O_CLOEXEC);
333 ASSERT_LE(0, path_beneath.parent_fd);
334 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
335 &path_beneath, 0));
336 ASSERT_EQ(0, close(path_beneath.parent_fd));
337
338 /* Tests with a ruleset FD. */
339 path_beneath.parent_fd = ruleset_fd;
340 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
341 &path_beneath, 0));
342 ASSERT_EQ(EBADFD, errno);
343
344 /* Checks unhandled allowed_access. */
345 path_beneath.parent_fd = open(dir_s1d2, O_PATH | O_DIRECTORY |
346 O_CLOEXEC);
347 ASSERT_LE(0, path_beneath.parent_fd);
348
349 /* Test with legitimate values. */
350 path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_EXECUTE;
351 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
352 &path_beneath, 0));
353 ASSERT_EQ(EINVAL, errno);
354 path_beneath.allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE;
355
356 /* Test with unknown (64-bits) value. */
357 path_beneath.allowed_access |= (1ULL << 60);
358 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
359 &path_beneath, 0));
360 ASSERT_EQ(EINVAL, errno);
361 path_beneath.allowed_access &= ~(1ULL << 60);
362
363 /* Test with no access. */
364 path_beneath.allowed_access = 0;
365 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
366 &path_beneath, 0));
367 ASSERT_EQ(ENOMSG, errno);
368 path_beneath.allowed_access &= ~(1ULL << 60);
369
370 ASSERT_EQ(0, close(path_beneath.parent_fd));
371
372 /* Enforces the ruleset. */
373 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
374 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
375
376 ASSERT_EQ(0, close(ruleset_fd));
377 }
378
379 #define ACCESS_FILE ( \
380 LANDLOCK_ACCESS_FS_EXECUTE | \
381 LANDLOCK_ACCESS_FS_WRITE_FILE | \
382 LANDLOCK_ACCESS_FS_READ_FILE)
383
384 #define ACCESS_LAST LANDLOCK_ACCESS_FS_MAKE_SYM
385
386 #define ACCESS_ALL ( \
387 ACCESS_FILE | \
388 LANDLOCK_ACCESS_FS_READ_DIR | \
389 LANDLOCK_ACCESS_FS_REMOVE_DIR | \
390 LANDLOCK_ACCESS_FS_REMOVE_FILE | \
391 LANDLOCK_ACCESS_FS_MAKE_CHAR | \
392 LANDLOCK_ACCESS_FS_MAKE_DIR | \
393 LANDLOCK_ACCESS_FS_MAKE_REG | \
394 LANDLOCK_ACCESS_FS_MAKE_SOCK | \
395 LANDLOCK_ACCESS_FS_MAKE_FIFO | \
396 LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
397 ACCESS_LAST)
398
TEST_F_FORK(layout1,file_access_rights)399 TEST_F_FORK(layout1, file_access_rights)
400 {
401 __u64 access;
402 int err;
403 struct landlock_path_beneath_attr path_beneath = {};
404 struct landlock_ruleset_attr ruleset_attr = {
405 .handled_access_fs = ACCESS_ALL,
406 };
407 const int ruleset_fd = landlock_create_ruleset(&ruleset_attr,
408 sizeof(ruleset_attr), 0);
409
410 ASSERT_LE(0, ruleset_fd);
411
412 /* Tests access rights for files. */
413 path_beneath.parent_fd = open(file1_s1d2, O_PATH | O_CLOEXEC);
414 ASSERT_LE(0, path_beneath.parent_fd);
415 for (access = 1; access <= ACCESS_LAST; access <<= 1) {
416 path_beneath.allowed_access = access;
417 err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
418 &path_beneath, 0);
419 if ((access | ACCESS_FILE) == ACCESS_FILE) {
420 ASSERT_EQ(0, err);
421 } else {
422 ASSERT_EQ(-1, err);
423 ASSERT_EQ(EINVAL, errno);
424 }
425 }
426 ASSERT_EQ(0, close(path_beneath.parent_fd));
427 }
428
add_path_beneath(struct __test_metadata * const _metadata,const int ruleset_fd,const __u64 allowed_access,const char * const path)429 static void add_path_beneath(struct __test_metadata *const _metadata,
430 const int ruleset_fd, const __u64 allowed_access,
431 const char *const path)
432 {
433 struct landlock_path_beneath_attr path_beneath = {
434 .allowed_access = allowed_access,
435 };
436
437 path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC);
438 ASSERT_LE(0, path_beneath.parent_fd) {
439 TH_LOG("Failed to open directory \"%s\": %s", path,
440 strerror(errno));
441 }
442 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
443 &path_beneath, 0)) {
444 TH_LOG("Failed to update the ruleset with \"%s\": %s", path,
445 strerror(errno));
446 }
447 ASSERT_EQ(0, close(path_beneath.parent_fd));
448 }
449
450 struct rule {
451 const char *path;
452 __u64 access;
453 };
454
455 #define ACCESS_RO ( \
456 LANDLOCK_ACCESS_FS_READ_FILE | \
457 LANDLOCK_ACCESS_FS_READ_DIR)
458
459 #define ACCESS_RW ( \
460 ACCESS_RO | \
461 LANDLOCK_ACCESS_FS_WRITE_FILE)
462
create_ruleset(struct __test_metadata * const _metadata,const __u64 handled_access_fs,const struct rule rules[])463 static int create_ruleset(struct __test_metadata *const _metadata,
464 const __u64 handled_access_fs, const struct rule rules[])
465 {
466 int ruleset_fd, i;
467 struct landlock_ruleset_attr ruleset_attr = {
468 .handled_access_fs = handled_access_fs,
469 };
470
471 ASSERT_NE(NULL, rules) {
472 TH_LOG("No rule list");
473 }
474 ASSERT_NE(NULL, rules[0].path) {
475 TH_LOG("Empty rule list");
476 }
477
478 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
479 sizeof(ruleset_attr), 0);
480 ASSERT_LE(0, ruleset_fd) {
481 TH_LOG("Failed to create a ruleset: %s", strerror(errno));
482 }
483
484 for (i = 0; rules[i].path; i++) {
485 add_path_beneath(_metadata, ruleset_fd, rules[i].access,
486 rules[i].path);
487 }
488 return ruleset_fd;
489 }
490
enforce_ruleset(struct __test_metadata * const _metadata,const int ruleset_fd)491 static void enforce_ruleset(struct __test_metadata *const _metadata,
492 const int ruleset_fd)
493 {
494 ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
495 ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) {
496 TH_LOG("Failed to enforce ruleset: %s", strerror(errno));
497 }
498 }
499
TEST_F_FORK(layout1,proc_nsfs)500 TEST_F_FORK(layout1, proc_nsfs)
501 {
502 const struct rule rules[] = {
503 {
504 .path = "/dev/null",
505 .access = LANDLOCK_ACCESS_FS_READ_FILE |
506 LANDLOCK_ACCESS_FS_WRITE_FILE,
507 },
508 {}
509 };
510 struct landlock_path_beneath_attr path_beneath;
511 const int ruleset_fd = create_ruleset(_metadata, rules[0].access |
512 LANDLOCK_ACCESS_FS_READ_DIR, rules);
513
514 ASSERT_LE(0, ruleset_fd);
515 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
516
517 enforce_ruleset(_metadata, ruleset_fd);
518
519 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
520 ASSERT_EQ(EACCES, test_open("/dev", O_RDONLY));
521 ASSERT_EQ(0, test_open("/dev/null", O_RDONLY));
522 ASSERT_EQ(EACCES, test_open("/dev/full", O_RDONLY));
523
524 ASSERT_EQ(EACCES, test_open("/proc", O_RDONLY));
525 ASSERT_EQ(EACCES, test_open("/proc/self", O_RDONLY));
526 ASSERT_EQ(EACCES, test_open("/proc/self/ns", O_RDONLY));
527 /*
528 * Because nsfs is an internal filesystem, /proc/self/ns/mnt is a
529 * disconnected path. Such path cannot be identified and must then be
530 * allowed.
531 */
532 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
533
534 /*
535 * Checks that it is not possible to add nsfs-like filesystem
536 * references to a ruleset.
537 */
538 path_beneath.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE |
539 LANDLOCK_ACCESS_FS_WRITE_FILE,
540 path_beneath.parent_fd = open("/proc/self/ns/mnt", O_PATH | O_CLOEXEC);
541 ASSERT_LE(0, path_beneath.parent_fd);
542 ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
543 &path_beneath, 0));
544 ASSERT_EQ(EBADFD, errno);
545 ASSERT_EQ(0, close(path_beneath.parent_fd));
546 }
547
TEST_F_FORK(layout1,unpriv)548 TEST_F_FORK(layout1, unpriv) {
549 const struct rule rules[] = {
550 {
551 .path = dir_s1d2,
552 .access = ACCESS_RO,
553 },
554 {}
555 };
556 int ruleset_fd;
557
558 drop_caps(_metadata);
559
560 ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
561 ASSERT_LE(0, ruleset_fd);
562 ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
563 ASSERT_EQ(EPERM, errno);
564
565 /* enforce_ruleset() calls prctl(no_new_privs). */
566 enforce_ruleset(_metadata, ruleset_fd);
567 ASSERT_EQ(0, close(ruleset_fd));
568 }
569
TEST_F_FORK(layout1,effective_access)570 TEST_F_FORK(layout1, effective_access)
571 {
572 const struct rule rules[] = {
573 {
574 .path = dir_s1d2,
575 .access = ACCESS_RO,
576 },
577 {
578 .path = file1_s2d2,
579 .access = LANDLOCK_ACCESS_FS_READ_FILE |
580 LANDLOCK_ACCESS_FS_WRITE_FILE,
581 },
582 {}
583 };
584 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
585 char buf;
586 int reg_fd;
587
588 ASSERT_LE(0, ruleset_fd);
589 enforce_ruleset(_metadata, ruleset_fd);
590 ASSERT_EQ(0, close(ruleset_fd));
591
592 /* Tests on a directory. */
593 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
594 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
595 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
596 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
597 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
598 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
599 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
600
601 /* Tests on a file. */
602 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY));
603 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
604
605 /* Checks effective read and write actions. */
606 reg_fd = open(file1_s2d2, O_RDWR | O_CLOEXEC);
607 ASSERT_LE(0, reg_fd);
608 ASSERT_EQ(1, write(reg_fd, ".", 1));
609 ASSERT_LE(0, lseek(reg_fd, 0, SEEK_SET));
610 ASSERT_EQ(1, read(reg_fd, &buf, 1));
611 ASSERT_EQ('.', buf);
612 ASSERT_EQ(0, close(reg_fd));
613
614 /* Just in case, double-checks effective actions. */
615 reg_fd = open(file1_s2d2, O_RDONLY | O_CLOEXEC);
616 ASSERT_LE(0, reg_fd);
617 ASSERT_EQ(-1, write(reg_fd, &buf, 1));
618 ASSERT_EQ(EBADF, errno);
619 ASSERT_EQ(0, close(reg_fd));
620 }
621
TEST_F_FORK(layout1,unhandled_access)622 TEST_F_FORK(layout1, unhandled_access)
623 {
624 const struct rule rules[] = {
625 {
626 .path = dir_s1d2,
627 .access = ACCESS_RO,
628 },
629 {}
630 };
631 /* Here, we only handle read accesses, not write accesses. */
632 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules);
633
634 ASSERT_LE(0, ruleset_fd);
635 enforce_ruleset(_metadata, ruleset_fd);
636 ASSERT_EQ(0, close(ruleset_fd));
637
638 /*
639 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE,
640 * opening for write-only should be allowed, but not read-write.
641 */
642 ASSERT_EQ(0, test_open(file1_s1d1, O_WRONLY));
643 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
644
645 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
646 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
647 }
648
TEST_F_FORK(layout1,ruleset_overlap)649 TEST_F_FORK(layout1, ruleset_overlap)
650 {
651 const struct rule rules[] = {
652 /* These rules should be ORed among them. */
653 {
654 .path = dir_s1d2,
655 .access = LANDLOCK_ACCESS_FS_READ_FILE |
656 LANDLOCK_ACCESS_FS_WRITE_FILE,
657 },
658 {
659 .path = dir_s1d2,
660 .access = LANDLOCK_ACCESS_FS_READ_FILE |
661 LANDLOCK_ACCESS_FS_READ_DIR,
662 },
663 {}
664 };
665 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
666
667 ASSERT_LE(0, ruleset_fd);
668 enforce_ruleset(_metadata, ruleset_fd);
669 ASSERT_EQ(0, close(ruleset_fd));
670
671 /* Checks s1d1 hierarchy. */
672 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
673 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
674 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
675 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
676
677 /* Checks s1d2 hierarchy. */
678 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
679 ASSERT_EQ(0, test_open(file1_s1d2, O_WRONLY));
680 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
681 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
682
683 /* Checks s1d3 hierarchy. */
684 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
685 ASSERT_EQ(0, test_open(file1_s1d3, O_WRONLY));
686 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
687 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
688 }
689
TEST_F_FORK(layout1,non_overlapping_accesses)690 TEST_F_FORK(layout1, non_overlapping_accesses)
691 {
692 const struct rule layer1[] = {
693 {
694 .path = dir_s1d2,
695 .access = LANDLOCK_ACCESS_FS_MAKE_REG,
696 },
697 {}
698 };
699 const struct rule layer2[] = {
700 {
701 .path = dir_s1d3,
702 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
703 },
704 {}
705 };
706 int ruleset_fd;
707
708 ASSERT_EQ(0, unlink(file1_s1d1));
709 ASSERT_EQ(0, unlink(file1_s1d2));
710
711 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG,
712 layer1);
713 ASSERT_LE(0, ruleset_fd);
714 enforce_ruleset(_metadata, ruleset_fd);
715 ASSERT_EQ(0, close(ruleset_fd));
716
717 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
718 ASSERT_EQ(EACCES, errno);
719 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
720 ASSERT_EQ(0, unlink(file1_s1d2));
721
722 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE,
723 layer2);
724 ASSERT_LE(0, ruleset_fd);
725 enforce_ruleset(_metadata, ruleset_fd);
726 ASSERT_EQ(0, close(ruleset_fd));
727
728 /* Unchanged accesses for file creation. */
729 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0));
730 ASSERT_EQ(EACCES, errno);
731 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0));
732
733 /* Checks file removing. */
734 ASSERT_EQ(-1, unlink(file1_s1d2));
735 ASSERT_EQ(EACCES, errno);
736 ASSERT_EQ(0, unlink(file1_s1d3));
737 }
738
TEST_F_FORK(layout1,interleaved_masked_accesses)739 TEST_F_FORK(layout1, interleaved_masked_accesses)
740 {
741 /*
742 * Checks overly restrictive rules:
743 * layer 1: allows R s1d1/s1d2/s1d3/file1
744 * layer 2: allows RW s1d1/s1d2/s1d3
745 * allows W s1d1/s1d2
746 * denies R s1d1/s1d2
747 * layer 3: allows R s1d1
748 * layer 4: allows R s1d1/s1d2
749 * denies W s1d1/s1d2
750 * layer 5: allows R s1d1/s1d2
751 * layer 6: allows X ----
752 * layer 7: allows W s1d1/s1d2
753 * denies R s1d1/s1d2
754 */
755 const struct rule layer1_read[] = {
756 /* Allows read access to file1_s1d3 with the first layer. */
757 {
758 .path = file1_s1d3,
759 .access = LANDLOCK_ACCESS_FS_READ_FILE,
760 },
761 {}
762 };
763 /* First rule with write restrictions. */
764 const struct rule layer2_read_write[] = {
765 /* Start by granting read-write access via its parent directory... */
766 {
767 .path = dir_s1d3,
768 .access = LANDLOCK_ACCESS_FS_READ_FILE |
769 LANDLOCK_ACCESS_FS_WRITE_FILE,
770 },
771 /* ...but also denies read access via its grandparent directory. */
772 {
773 .path = dir_s1d2,
774 .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
775 },
776 {}
777 };
778 const struct rule layer3_read[] = {
779 /* Allows read access via its great-grandparent directory. */
780 {
781 .path = dir_s1d1,
782 .access = LANDLOCK_ACCESS_FS_READ_FILE,
783 },
784 {}
785 };
786 const struct rule layer4_read_write[] = {
787 /*
788 * Try to confuse the deny access by denying write (but not
789 * read) access via its grandparent directory.
790 */
791 {
792 .path = dir_s1d2,
793 .access = LANDLOCK_ACCESS_FS_READ_FILE,
794 },
795 {}
796 };
797 const struct rule layer5_read[] = {
798 /*
799 * Try to override layer2's deny read access by explicitly
800 * allowing read access via file1_s1d3's grandparent.
801 */
802 {
803 .path = dir_s1d2,
804 .access = LANDLOCK_ACCESS_FS_READ_FILE,
805 },
806 {}
807 };
808 const struct rule layer6_execute[] = {
809 /*
810 * Restricts an unrelated file hierarchy with a new access
811 * (non-overlapping) type.
812 */
813 {
814 .path = dir_s2d1,
815 .access = LANDLOCK_ACCESS_FS_EXECUTE,
816 },
817 {}
818 };
819 const struct rule layer7_read_write[] = {
820 /*
821 * Finally, denies read access to file1_s1d3 via its
822 * grandparent.
823 */
824 {
825 .path = dir_s1d2,
826 .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
827 },
828 {}
829 };
830 int ruleset_fd;
831
832 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
833 layer1_read);
834 ASSERT_LE(0, ruleset_fd);
835 enforce_ruleset(_metadata, ruleset_fd);
836 ASSERT_EQ(0, close(ruleset_fd));
837
838 /* Checks that read access is granted for file1_s1d3 with layer 1. */
839 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
840 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
841 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
842
843 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE |
844 LANDLOCK_ACCESS_FS_WRITE_FILE, layer2_read_write);
845 ASSERT_LE(0, ruleset_fd);
846 enforce_ruleset(_metadata, ruleset_fd);
847 ASSERT_EQ(0, close(ruleset_fd));
848
849 /* Checks that previous access rights are unchanged with layer 2. */
850 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
851 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
852 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
853
854 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
855 layer3_read);
856 ASSERT_LE(0, ruleset_fd);
857 enforce_ruleset(_metadata, ruleset_fd);
858 ASSERT_EQ(0, close(ruleset_fd));
859
860 /* Checks that previous access rights are unchanged with layer 3. */
861 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR));
862 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
863 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY));
864
865 /* This time, denies write access for the file hierarchy. */
866 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE |
867 LANDLOCK_ACCESS_FS_WRITE_FILE, layer4_read_write);
868 ASSERT_LE(0, ruleset_fd);
869 enforce_ruleset(_metadata, ruleset_fd);
870 ASSERT_EQ(0, close(ruleset_fd));
871
872 /*
873 * Checks that the only change with layer 4 is that write access is
874 * denied.
875 */
876 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
877 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
878 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
879 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
880
881 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
882 layer5_read);
883 ASSERT_LE(0, ruleset_fd);
884 enforce_ruleset(_metadata, ruleset_fd);
885 ASSERT_EQ(0, close(ruleset_fd));
886
887 /* Checks that previous access rights are unchanged with layer 5. */
888 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
889 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
890 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
891 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
892
893 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE,
894 layer6_execute);
895 ASSERT_LE(0, ruleset_fd);
896 enforce_ruleset(_metadata, ruleset_fd);
897 ASSERT_EQ(0, close(ruleset_fd));
898
899 /* Checks that previous access rights are unchanged with layer 6. */
900 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
901 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
902 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
903 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
904
905 ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE |
906 LANDLOCK_ACCESS_FS_WRITE_FILE, layer7_read_write);
907 ASSERT_LE(0, ruleset_fd);
908 enforce_ruleset(_metadata, ruleset_fd);
909 ASSERT_EQ(0, close(ruleset_fd));
910
911 /* Checks read access is now denied with layer 7. */
912 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
913 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
914 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY));
915 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY));
916 }
917
TEST_F_FORK(layout1,inherit_subset)918 TEST_F_FORK(layout1, inherit_subset)
919 {
920 const struct rule rules[] = {
921 {
922 .path = dir_s1d2,
923 .access = LANDLOCK_ACCESS_FS_READ_FILE |
924 LANDLOCK_ACCESS_FS_READ_DIR,
925 },
926 {}
927 };
928 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
929
930 ASSERT_LE(0, ruleset_fd);
931 enforce_ruleset(_metadata, ruleset_fd);
932
933 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
934 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
935
936 /* Write access is forbidden. */
937 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
938 /* Readdir access is allowed. */
939 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
940
941 /* Write access is forbidden. */
942 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
943 /* Readdir access is allowed. */
944 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
945
946 /*
947 * Tests shared rule extension: the following rules should not grant
948 * any new access, only remove some. Once enforced, these rules are
949 * ANDed with the previous ones.
950 */
951 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
952 dir_s1d2);
953 /*
954 * According to ruleset_fd, dir_s1d2 should now have the
955 * LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE
956 * access rights (even if this directory is opened a second time).
957 * However, when enforcing this updated ruleset, the ruleset tied to
958 * the current process (i.e. its domain) will still only have the
959 * dir_s1d2 with LANDLOCK_ACCESS_FS_READ_FILE and
960 * LANDLOCK_ACCESS_FS_READ_DIR accesses, but
961 * LANDLOCK_ACCESS_FS_WRITE_FILE must not be allowed because it would
962 * be a privilege escalation.
963 */
964 enforce_ruleset(_metadata, ruleset_fd);
965
966 /* Same tests and results as above. */
967 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
968 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
969
970 /* It is still forbidden to write in file1_s1d2. */
971 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
972 /* Readdir access is still allowed. */
973 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
974
975 /* It is still forbidden to write in file1_s1d3. */
976 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
977 /* Readdir access is still allowed. */
978 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
979
980 /*
981 * Try to get more privileges by adding new access rights to the parent
982 * directory: dir_s1d1.
983 */
984 add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1);
985 enforce_ruleset(_metadata, ruleset_fd);
986
987 /* Same tests and results as above. */
988 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
989 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
990
991 /* It is still forbidden to write in file1_s1d2. */
992 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
993 /* Readdir access is still allowed. */
994 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
995
996 /* It is still forbidden to write in file1_s1d3. */
997 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
998 /* Readdir access is still allowed. */
999 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1000
1001 /*
1002 * Now, dir_s1d3 get a new rule tied to it, only allowing
1003 * LANDLOCK_ACCESS_FS_WRITE_FILE. The (kernel internal) difference is
1004 * that there was no rule tied to it before.
1005 */
1006 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
1007 dir_s1d3);
1008 enforce_ruleset(_metadata, ruleset_fd);
1009 ASSERT_EQ(0, close(ruleset_fd));
1010
1011 /*
1012 * Same tests and results as above, except for open(dir_s1d3) which is
1013 * now denied because the new rule mask the rule previously inherited
1014 * from dir_s1d2.
1015 */
1016
1017 /* Same tests and results as above. */
1018 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1019 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1020
1021 /* It is still forbidden to write in file1_s1d2. */
1022 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1023 /* Readdir access is still allowed. */
1024 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1025
1026 /* It is still forbidden to write in file1_s1d3. */
1027 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1028 /*
1029 * Readdir of dir_s1d3 is still allowed because of the OR policy inside
1030 * the same layer.
1031 */
1032 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1033 }
1034
TEST_F_FORK(layout1,inherit_superset)1035 TEST_F_FORK(layout1, inherit_superset)
1036 {
1037 const struct rule rules[] = {
1038 {
1039 .path = dir_s1d3,
1040 .access = ACCESS_RO,
1041 },
1042 {}
1043 };
1044 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1045
1046 ASSERT_LE(0, ruleset_fd);
1047 enforce_ruleset(_metadata, ruleset_fd);
1048
1049 /* Readdir access is denied for dir_s1d2. */
1050 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1051 /* Readdir access is allowed for dir_s1d3. */
1052 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1053 /* File access is allowed for file1_s1d3. */
1054 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1055
1056 /* Now dir_s1d2, parent of dir_s1d3, gets a new rule tied to it. */
1057 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_READ_FILE |
1058 LANDLOCK_ACCESS_FS_READ_DIR, dir_s1d2);
1059 enforce_ruleset(_metadata, ruleset_fd);
1060 ASSERT_EQ(0, close(ruleset_fd));
1061
1062 /* Readdir access is still denied for dir_s1d2. */
1063 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1064 /* Readdir access is still allowed for dir_s1d3. */
1065 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1066 /* File access is still allowed for file1_s1d3. */
1067 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1068 }
1069
TEST_F_FORK(layout1,max_layers)1070 TEST_F_FORK(layout1, max_layers)
1071 {
1072 int i, err;
1073 const struct rule rules[] = {
1074 {
1075 .path = dir_s1d2,
1076 .access = ACCESS_RO,
1077 },
1078 {}
1079 };
1080 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1081
1082 ASSERT_LE(0, ruleset_fd);
1083 for (i = 0; i < 64; i++)
1084 enforce_ruleset(_metadata, ruleset_fd);
1085
1086 for (i = 0; i < 2; i++) {
1087 err = landlock_restrict_self(ruleset_fd, 0);
1088 ASSERT_EQ(-1, err);
1089 ASSERT_EQ(E2BIG, errno);
1090 }
1091 ASSERT_EQ(0, close(ruleset_fd));
1092 }
1093
TEST_F_FORK(layout1,empty_or_same_ruleset)1094 TEST_F_FORK(layout1, empty_or_same_ruleset)
1095 {
1096 struct landlock_ruleset_attr ruleset_attr = {};
1097 int ruleset_fd;
1098
1099 /* Tests empty handled_access_fs. */
1100 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
1101 sizeof(ruleset_attr), 0);
1102 ASSERT_LE(-1, ruleset_fd);
1103 ASSERT_EQ(ENOMSG, errno);
1104
1105 /* Enforces policy which deny read access to all files. */
1106 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE;
1107 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
1108 sizeof(ruleset_attr), 0);
1109 ASSERT_LE(0, ruleset_fd);
1110 enforce_ruleset(_metadata, ruleset_fd);
1111 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1112 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1113
1114 /* Nests a policy which deny read access to all directories. */
1115 ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR;
1116 ruleset_fd = landlock_create_ruleset(&ruleset_attr,
1117 sizeof(ruleset_attr), 0);
1118 ASSERT_LE(0, ruleset_fd);
1119 enforce_ruleset(_metadata, ruleset_fd);
1120 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
1121 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1122
1123 /* Enforces a second time with the same ruleset. */
1124 enforce_ruleset(_metadata, ruleset_fd);
1125 ASSERT_EQ(0, close(ruleset_fd));
1126 }
1127
TEST_F_FORK(layout1,rule_on_mountpoint)1128 TEST_F_FORK(layout1, rule_on_mountpoint)
1129 {
1130 const struct rule rules[] = {
1131 {
1132 .path = dir_s1d1,
1133 .access = ACCESS_RO,
1134 },
1135 {
1136 /* dir_s3d2 is a mount point. */
1137 .path = dir_s3d2,
1138 .access = ACCESS_RO,
1139 },
1140 {}
1141 };
1142 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1143
1144 ASSERT_LE(0, ruleset_fd);
1145 enforce_ruleset(_metadata, ruleset_fd);
1146 ASSERT_EQ(0, close(ruleset_fd));
1147
1148 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1149
1150 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1151
1152 ASSERT_EQ(EACCES, test_open(dir_s3d1, O_RDONLY));
1153 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1154 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1155 }
1156
TEST_F_FORK(layout1,rule_over_mountpoint)1157 TEST_F_FORK(layout1, rule_over_mountpoint)
1158 {
1159 const struct rule rules[] = {
1160 {
1161 .path = dir_s1d1,
1162 .access = ACCESS_RO,
1163 },
1164 {
1165 /* dir_s3d2 is a mount point. */
1166 .path = dir_s3d1,
1167 .access = ACCESS_RO,
1168 },
1169 {}
1170 };
1171 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1172
1173 ASSERT_LE(0, ruleset_fd);
1174 enforce_ruleset(_metadata, ruleset_fd);
1175 ASSERT_EQ(0, close(ruleset_fd));
1176
1177 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1178
1179 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY));
1180
1181 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
1182 ASSERT_EQ(0, test_open(dir_s3d2, O_RDONLY));
1183 ASSERT_EQ(0, test_open(dir_s3d3, O_RDONLY));
1184 }
1185
1186 /*
1187 * This test verifies that we can apply a landlock rule on the root directory
1188 * (which might require special handling).
1189 */
TEST_F_FORK(layout1,rule_over_root_allow_then_deny)1190 TEST_F_FORK(layout1, rule_over_root_allow_then_deny)
1191 {
1192 struct rule rules[] = {
1193 {
1194 .path = "/",
1195 .access = ACCESS_RO,
1196 },
1197 {}
1198 };
1199 int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1200
1201 ASSERT_LE(0, ruleset_fd);
1202 enforce_ruleset(_metadata, ruleset_fd);
1203 ASSERT_EQ(0, close(ruleset_fd));
1204
1205 /* Checks allowed access. */
1206 ASSERT_EQ(0, test_open("/", O_RDONLY));
1207 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1208
1209 rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE;
1210 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1211 ASSERT_LE(0, ruleset_fd);
1212 enforce_ruleset(_metadata, ruleset_fd);
1213 ASSERT_EQ(0, close(ruleset_fd));
1214
1215 /* Checks denied access (on a directory). */
1216 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1217 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1218 }
1219
TEST_F_FORK(layout1,rule_over_root_deny)1220 TEST_F_FORK(layout1, rule_over_root_deny)
1221 {
1222 const struct rule rules[] = {
1223 {
1224 .path = "/",
1225 .access = LANDLOCK_ACCESS_FS_READ_FILE,
1226 },
1227 {}
1228 };
1229 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1230
1231 ASSERT_LE(0, ruleset_fd);
1232 enforce_ruleset(_metadata, ruleset_fd);
1233 ASSERT_EQ(0, close(ruleset_fd));
1234
1235 /* Checks denied access (on a directory). */
1236 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1237 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1238 }
1239
TEST_F_FORK(layout1,rule_inside_mount_ns)1240 TEST_F_FORK(layout1, rule_inside_mount_ns)
1241 {
1242 const struct rule rules[] = {
1243 {
1244 .path = "s3d3",
1245 .access = ACCESS_RO,
1246 },
1247 {}
1248 };
1249 int ruleset_fd;
1250
1251 set_cap(_metadata, CAP_SYS_ADMIN);
1252 ASSERT_EQ(0, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3)) {
1253 TH_LOG("Failed to pivot root: %s", strerror(errno));
1254 };
1255 ASSERT_EQ(0, chdir("/"));
1256 clear_cap(_metadata, CAP_SYS_ADMIN);
1257
1258 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1259 ASSERT_LE(0, ruleset_fd);
1260 enforce_ruleset(_metadata, ruleset_fd);
1261 ASSERT_EQ(0, close(ruleset_fd));
1262
1263 ASSERT_EQ(0, test_open("s3d3", O_RDONLY));
1264 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1265 }
1266
TEST_F_FORK(layout1,mount_and_pivot)1267 TEST_F_FORK(layout1, mount_and_pivot)
1268 {
1269 const struct rule rules[] = {
1270 {
1271 .path = dir_s3d2,
1272 .access = ACCESS_RO,
1273 },
1274 {}
1275 };
1276 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1277
1278 ASSERT_LE(0, ruleset_fd);
1279 enforce_ruleset(_metadata, ruleset_fd);
1280 ASSERT_EQ(0, close(ruleset_fd));
1281
1282 set_cap(_metadata, CAP_SYS_ADMIN);
1283 ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
1284 ASSERT_EQ(EPERM, errno);
1285 ASSERT_EQ(-1, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3));
1286 ASSERT_EQ(EPERM, errno);
1287 clear_cap(_metadata, CAP_SYS_ADMIN);
1288 }
1289
TEST_F_FORK(layout1,move_mount)1290 TEST_F_FORK(layout1, move_mount)
1291 {
1292 const struct rule rules[] = {
1293 {
1294 .path = dir_s3d2,
1295 .access = ACCESS_RO,
1296 },
1297 {}
1298 };
1299 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1300
1301 ASSERT_LE(0, ruleset_fd);
1302
1303 set_cap(_metadata, CAP_SYS_ADMIN);
1304 ASSERT_EQ(0, syscall(SYS_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1305 dir_s1d2, 0)) {
1306 TH_LOG("Failed to move mount: %s", strerror(errno));
1307 }
1308
1309 ASSERT_EQ(0, syscall(SYS_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD,
1310 dir_s3d2, 0));
1311 clear_cap(_metadata, CAP_SYS_ADMIN);
1312
1313 enforce_ruleset(_metadata, ruleset_fd);
1314 ASSERT_EQ(0, close(ruleset_fd));
1315
1316 set_cap(_metadata, CAP_SYS_ADMIN);
1317 ASSERT_EQ(-1, syscall(SYS_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD,
1318 dir_s1d2, 0));
1319 ASSERT_EQ(EPERM, errno);
1320 clear_cap(_metadata, CAP_SYS_ADMIN);
1321 }
1322
TEST_F_FORK(layout1,release_inodes)1323 TEST_F_FORK(layout1, release_inodes)
1324 {
1325 const struct rule rules[] = {
1326 {
1327 .path = dir_s1d1,
1328 .access = ACCESS_RO,
1329 },
1330 {
1331 .path = dir_s3d2,
1332 .access = ACCESS_RO,
1333 },
1334 {
1335 .path = dir_s3d3,
1336 .access = ACCESS_RO,
1337 },
1338 {}
1339 };
1340 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules);
1341
1342 ASSERT_LE(0, ruleset_fd);
1343 /* Unmount a file hierarchy while it is being used by a ruleset. */
1344 set_cap(_metadata, CAP_SYS_ADMIN);
1345 ASSERT_EQ(0, umount(dir_s3d2));
1346 clear_cap(_metadata, CAP_SYS_ADMIN);
1347
1348 enforce_ruleset(_metadata, ruleset_fd);
1349 ASSERT_EQ(0, close(ruleset_fd));
1350
1351 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
1352 ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY));
1353 /* This dir_s3d3 would not be allowed and does not exist anyway. */
1354 ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY));
1355 }
1356
1357 enum relative_access {
1358 REL_OPEN,
1359 REL_CHDIR,
1360 REL_CHROOT_ONLY,
1361 REL_CHROOT_CHDIR,
1362 };
1363
test_relative_path(struct __test_metadata * const _metadata,const enum relative_access rel)1364 static void test_relative_path(struct __test_metadata *const _metadata,
1365 const enum relative_access rel)
1366 {
1367 /*
1368 * Common layer to check that chroot doesn't ignore it (i.e. a chroot
1369 * is not a disconnected root directory).
1370 */
1371 const struct rule layer1_base[] = {
1372 {
1373 .path = TMP_DIR,
1374 .access = ACCESS_RO,
1375 },
1376 {}
1377 };
1378 const struct rule layer2_subs[] = {
1379 {
1380 .path = dir_s1d2,
1381 .access = ACCESS_RO,
1382 },
1383 {
1384 .path = dir_s2d2,
1385 .access = ACCESS_RO,
1386 },
1387 {}
1388 };
1389 int dirfd, ruleset_fd;
1390
1391 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
1392 ASSERT_LE(0, ruleset_fd);
1393 enforce_ruleset(_metadata, ruleset_fd);
1394 ASSERT_EQ(0, close(ruleset_fd));
1395
1396 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs);
1397
1398 ASSERT_LE(0, ruleset_fd);
1399 switch (rel) {
1400 case REL_OPEN:
1401 case REL_CHDIR:
1402 break;
1403 case REL_CHROOT_ONLY:
1404 ASSERT_EQ(0, chdir(dir_s2d2));
1405 break;
1406 case REL_CHROOT_CHDIR:
1407 ASSERT_EQ(0, chdir(dir_s1d2));
1408 break;
1409 default:
1410 ASSERT_TRUE(false);
1411 return;
1412 }
1413
1414 set_cap(_metadata, CAP_SYS_CHROOT);
1415 enforce_ruleset(_metadata, ruleset_fd);
1416
1417 switch (rel) {
1418 case REL_OPEN:
1419 dirfd = open(dir_s1d2, O_DIRECTORY);
1420 ASSERT_LE(0, dirfd);
1421 break;
1422 case REL_CHDIR:
1423 ASSERT_EQ(0, chdir(dir_s1d2));
1424 dirfd = AT_FDCWD;
1425 break;
1426 case REL_CHROOT_ONLY:
1427 /* Do chroot into dir_s1d2 (relative to dir_s2d2). */
1428 ASSERT_EQ(0, chroot("../../s1d1/s1d2")) {
1429 TH_LOG("Failed to chroot: %s", strerror(errno));
1430 }
1431 dirfd = AT_FDCWD;
1432 break;
1433 case REL_CHROOT_CHDIR:
1434 /* Do chroot into dir_s1d2. */
1435 ASSERT_EQ(0, chroot(".")) {
1436 TH_LOG("Failed to chroot: %s", strerror(errno));
1437 }
1438 dirfd = AT_FDCWD;
1439 break;
1440 }
1441
1442 ASSERT_EQ((rel == REL_CHROOT_CHDIR) ? 0 : EACCES,
1443 test_open_rel(dirfd, "..", O_RDONLY));
1444 ASSERT_EQ(0, test_open_rel(dirfd, ".", O_RDONLY));
1445
1446 if (rel == REL_CHROOT_ONLY) {
1447 /* The current directory is dir_s2d2. */
1448 ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY));
1449 } else {
1450 /* The current directory is dir_s1d2. */
1451 ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY));
1452 }
1453
1454 if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) {
1455 /* Checks the root dir_s1d2. */
1456 ASSERT_EQ(0, test_open_rel(dirfd, "/..", O_RDONLY));
1457 ASSERT_EQ(0, test_open_rel(dirfd, "/", O_RDONLY));
1458 ASSERT_EQ(0, test_open_rel(dirfd, "/f1", O_RDONLY));
1459 ASSERT_EQ(0, test_open_rel(dirfd, "/s1d3", O_RDONLY));
1460 }
1461
1462 if (rel != REL_CHROOT_CHDIR) {
1463 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s1d1", O_RDONLY));
1464 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2", O_RDONLY));
1465 ASSERT_EQ(0, test_open_rel(dirfd, "../../s1d1/s1d2/s1d3", O_RDONLY));
1466
1467 ASSERT_EQ(EACCES, test_open_rel(dirfd, "../../s2d1", O_RDONLY));
1468 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2", O_RDONLY));
1469 ASSERT_EQ(0, test_open_rel(dirfd, "../../s2d1/s2d2/s2d3", O_RDONLY));
1470 }
1471
1472 if (rel == REL_OPEN)
1473 ASSERT_EQ(0, close(dirfd));
1474 ASSERT_EQ(0, close(ruleset_fd));
1475 }
1476
TEST_F_FORK(layout1,relative_open)1477 TEST_F_FORK(layout1, relative_open)
1478 {
1479 test_relative_path(_metadata, REL_OPEN);
1480 }
1481
TEST_F_FORK(layout1,relative_chdir)1482 TEST_F_FORK(layout1, relative_chdir)
1483 {
1484 test_relative_path(_metadata, REL_CHDIR);
1485 }
1486
TEST_F_FORK(layout1,relative_chroot_only)1487 TEST_F_FORK(layout1, relative_chroot_only)
1488 {
1489 test_relative_path(_metadata, REL_CHROOT_ONLY);
1490 }
1491
TEST_F_FORK(layout1,relative_chroot_chdir)1492 TEST_F_FORK(layout1, relative_chroot_chdir)
1493 {
1494 test_relative_path(_metadata, REL_CHROOT_CHDIR);
1495 }
1496
copy_binary(struct __test_metadata * const _metadata,const char * const dst_path)1497 static void copy_binary(struct __test_metadata *const _metadata,
1498 const char *const dst_path)
1499 {
1500 int dst_fd, src_fd;
1501 struct stat statbuf;
1502
1503 dst_fd = open(dst_path, O_WRONLY | O_TRUNC | O_CLOEXEC);
1504 ASSERT_LE(0, dst_fd) {
1505 TH_LOG("Failed to open \"%s\": %s", dst_path,
1506 strerror(errno));
1507 }
1508 src_fd = open(BINARY_PATH, O_RDONLY | O_CLOEXEC);
1509 ASSERT_LE(0, src_fd) {
1510 TH_LOG("Failed to open \"" BINARY_PATH "\": %s",
1511 strerror(errno));
1512 }
1513 ASSERT_EQ(0, fstat(src_fd, &statbuf));
1514 ASSERT_EQ(statbuf.st_size, sendfile(dst_fd, src_fd, 0,
1515 statbuf.st_size));
1516 ASSERT_EQ(0, close(src_fd));
1517 ASSERT_EQ(0, close(dst_fd));
1518 }
1519
test_execute(struct __test_metadata * const _metadata,const int err,const char * const path)1520 static void test_execute(struct __test_metadata *const _metadata,
1521 const int err, const char *const path)
1522 {
1523 int status;
1524 char *const argv[] = {(char *)path, NULL};
1525 const pid_t child = fork();
1526
1527 ASSERT_LE(0, child);
1528 if (child == 0) {
1529 ASSERT_EQ(err ? -1 : 0, execve(path, argv, NULL)) {
1530 TH_LOG("Failed to execute \"%s\": %s", path,
1531 strerror(errno));
1532 };
1533 ASSERT_EQ(err, errno);
1534 _exit(_metadata->passed ? 2 : 1);
1535 return;
1536 }
1537 ASSERT_EQ(child, waitpid(child, &status, 0));
1538 ASSERT_EQ(1, WIFEXITED(status));
1539 ASSERT_EQ(err ? 2 : 0, WEXITSTATUS(status)) {
1540 TH_LOG("Unexpected return code for \"%s\": %s", path,
1541 strerror(errno));
1542 };
1543 }
1544
TEST_F_FORK(layout1,execute)1545 TEST_F_FORK(layout1, execute)
1546 {
1547 const struct rule rules[] = {
1548 {
1549 .path = dir_s1d2,
1550 .access = LANDLOCK_ACCESS_FS_EXECUTE,
1551 },
1552 {}
1553 };
1554 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1555 rules);
1556
1557 ASSERT_LE(0, ruleset_fd);
1558 copy_binary(_metadata, file1_s1d1);
1559 copy_binary(_metadata, file1_s1d2);
1560 copy_binary(_metadata, file1_s1d3);
1561
1562 enforce_ruleset(_metadata, ruleset_fd);
1563 ASSERT_EQ(0, close(ruleset_fd));
1564
1565 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
1566 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
1567 test_execute(_metadata, EACCES, file1_s1d1);
1568
1569 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
1570 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
1571 test_execute(_metadata, 0, file1_s1d2);
1572
1573 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
1574 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1575 test_execute(_metadata, 0, file1_s1d3);
1576 }
1577
TEST_F_FORK(layout1,link)1578 TEST_F_FORK(layout1, link)
1579 {
1580 const struct rule rules[] = {
1581 {
1582 .path = dir_s1d2,
1583 .access = LANDLOCK_ACCESS_FS_MAKE_REG,
1584 },
1585 {}
1586 };
1587 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1588 rules);
1589
1590 ASSERT_LE(0, ruleset_fd);
1591
1592 ASSERT_EQ(0, unlink(file1_s1d1));
1593 ASSERT_EQ(0, unlink(file1_s1d2));
1594 ASSERT_EQ(0, unlink(file1_s1d3));
1595
1596 enforce_ruleset(_metadata, ruleset_fd);
1597 ASSERT_EQ(0, close(ruleset_fd));
1598
1599 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
1600 ASSERT_EQ(EACCES, errno);
1601 /* Denies linking because of reparenting. */
1602 ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
1603 ASSERT_EQ(EXDEV, errno);
1604 ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
1605 ASSERT_EQ(EXDEV, errno);
1606
1607 ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
1608 ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
1609 }
1610
TEST_F_FORK(layout1,rename_file)1611 TEST_F_FORK(layout1, rename_file)
1612 {
1613 const struct rule rules[] = {
1614 {
1615 .path = dir_s1d3,
1616 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
1617 },
1618 {
1619 .path = dir_s2d2,
1620 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
1621 },
1622 {}
1623 };
1624 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1625 rules);
1626
1627 ASSERT_LE(0, ruleset_fd);
1628
1629 ASSERT_EQ(0, unlink(file1_s1d1));
1630 ASSERT_EQ(0, unlink(file1_s1d2));
1631
1632 enforce_ruleset(_metadata, ruleset_fd);
1633 ASSERT_EQ(0, close(ruleset_fd));
1634
1635 /*
1636 * Tries to replace a file, from a directory that allows file removal,
1637 * but to a different directory (which also allows file removal).
1638 */
1639 ASSERT_EQ(-1, rename(file1_s2d3, file1_s1d3));
1640 ASSERT_EQ(EXDEV, errno);
1641 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, file1_s1d3,
1642 RENAME_EXCHANGE));
1643 ASSERT_EQ(EXDEV, errno);
1644 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d3, AT_FDCWD, dir_s1d3,
1645 RENAME_EXCHANGE));
1646 ASSERT_EQ(EXDEV, errno);
1647
1648 /*
1649 * Tries to replace a file, from a directory that denies file removal,
1650 * to a different directory (which allows file removal).
1651 */
1652 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
1653 ASSERT_EQ(EXDEV, errno);
1654 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, file1_s1d3,
1655 RENAME_EXCHANGE));
1656 ASSERT_EQ(EXDEV, errno);
1657 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s1d3,
1658 RENAME_EXCHANGE));
1659 ASSERT_EQ(EXDEV, errno);
1660
1661 /* Exchanges files and directories that partially allow removal. */
1662 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1,
1663 RENAME_EXCHANGE));
1664 ASSERT_EQ(EACCES, errno);
1665 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2,
1666 RENAME_EXCHANGE));
1667 ASSERT_EQ(EACCES, errno);
1668
1669 /* Renames files with different parents. */
1670 ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
1671 ASSERT_EQ(EXDEV, errno);
1672 ASSERT_EQ(0, unlink(file1_s1d3));
1673 ASSERT_EQ(-1, rename(file1_s2d1, file1_s1d3));
1674 ASSERT_EQ(EXDEV, errno);
1675
1676 /* Exchanges and renames files with same parent. */
1677 ASSERT_EQ(0, renameat2(AT_FDCWD, file2_s2d3, AT_FDCWD, file1_s2d3,
1678 RENAME_EXCHANGE));
1679 ASSERT_EQ(0, rename(file2_s2d3, file1_s2d3));
1680
1681 /* Exchanges files and directories with same parent, twice. */
1682 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
1683 RENAME_EXCHANGE));
1684 ASSERT_EQ(0, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s2d3,
1685 RENAME_EXCHANGE));
1686 }
1687
TEST_F_FORK(layout1,rename_dir)1688 TEST_F_FORK(layout1, rename_dir)
1689 {
1690 const struct rule rules[] = {
1691 {
1692 .path = dir_s1d2,
1693 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
1694 },
1695 {
1696 .path = dir_s2d1,
1697 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
1698 },
1699 {}
1700 };
1701 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1702 rules);
1703
1704 ASSERT_LE(0, ruleset_fd);
1705
1706 /* Empties dir_s1d3 to allow renaming. */
1707 ASSERT_EQ(0, unlink(file1_s1d3));
1708 ASSERT_EQ(0, unlink(file2_s1d3));
1709
1710 enforce_ruleset(_metadata, ruleset_fd);
1711 ASSERT_EQ(0, close(ruleset_fd));
1712
1713 /* Exchanges and renames directory to a different parent. */
1714 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3,
1715 RENAME_EXCHANGE));
1716 ASSERT_EQ(EXDEV, errno);
1717 ASSERT_EQ(-1, rename(dir_s2d3, dir_s1d3));
1718 ASSERT_EQ(EXDEV, errno);
1719 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d2, AT_FDCWD, dir_s1d3,
1720 RENAME_EXCHANGE));
1721 ASSERT_EQ(EXDEV, errno);
1722
1723 /*
1724 * Exchanges directory to the same parent, which doesn't allow
1725 * directory removal.
1726 */
1727 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1,
1728 RENAME_EXCHANGE));
1729 ASSERT_EQ(EACCES, errno);
1730 ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2,
1731 RENAME_EXCHANGE));
1732 ASSERT_EQ(EACCES, errno);
1733
1734 /*
1735 * Exchanges and renames directory to the same parent, which allows
1736 * directory removal.
1737 */
1738 ASSERT_EQ(0, renameat2(AT_FDCWD, dir_s1d3, AT_FDCWD, file1_s1d2,
1739 RENAME_EXCHANGE));
1740 ASSERT_EQ(0, unlink(dir_s1d3));
1741 ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
1742 ASSERT_EQ(0, rename(file1_s1d2, dir_s1d3));
1743 ASSERT_EQ(0, rmdir(dir_s1d3));
1744 }
1745
TEST_F_FORK(layout1,remove_dir)1746 TEST_F_FORK(layout1, remove_dir)
1747 {
1748 const struct rule rules[] = {
1749 {
1750 .path = dir_s1d2,
1751 .access = LANDLOCK_ACCESS_FS_REMOVE_DIR,
1752 },
1753 {}
1754 };
1755 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1756 rules);
1757
1758 ASSERT_LE(0, ruleset_fd);
1759
1760 ASSERT_EQ(0, unlink(file1_s1d1));
1761 ASSERT_EQ(0, unlink(file1_s1d2));
1762 ASSERT_EQ(0, unlink(file1_s1d3));
1763 ASSERT_EQ(0, unlink(file2_s1d3));
1764
1765 enforce_ruleset(_metadata, ruleset_fd);
1766 ASSERT_EQ(0, close(ruleset_fd));
1767
1768 ASSERT_EQ(0, rmdir(dir_s1d3));
1769 ASSERT_EQ(0, mkdir(dir_s1d3, 0700));
1770 ASSERT_EQ(0, unlinkat(AT_FDCWD, dir_s1d3, AT_REMOVEDIR));
1771
1772 /* dir_s1d2 itself cannot be removed. */
1773 ASSERT_EQ(-1, rmdir(dir_s1d2));
1774 ASSERT_EQ(EACCES, errno);
1775 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d2, AT_REMOVEDIR));
1776 ASSERT_EQ(EACCES, errno);
1777 ASSERT_EQ(-1, rmdir(dir_s1d1));
1778 ASSERT_EQ(EACCES, errno);
1779 ASSERT_EQ(-1, unlinkat(AT_FDCWD, dir_s1d1, AT_REMOVEDIR));
1780 ASSERT_EQ(EACCES, errno);
1781 }
1782
TEST_F_FORK(layout1,remove_file)1783 TEST_F_FORK(layout1, remove_file)
1784 {
1785 const struct rule rules[] = {
1786 {
1787 .path = dir_s1d2,
1788 .access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
1789 },
1790 {}
1791 };
1792 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1793 rules);
1794
1795 ASSERT_LE(0, ruleset_fd);
1796 enforce_ruleset(_metadata, ruleset_fd);
1797 ASSERT_EQ(0, close(ruleset_fd));
1798
1799 ASSERT_EQ(-1, unlink(file1_s1d1));
1800 ASSERT_EQ(EACCES, errno);
1801 ASSERT_EQ(-1, unlinkat(AT_FDCWD, file1_s1d1, 0));
1802 ASSERT_EQ(EACCES, errno);
1803 ASSERT_EQ(0, unlink(file1_s1d2));
1804 ASSERT_EQ(0, unlinkat(AT_FDCWD, file1_s1d3, 0));
1805 }
1806
test_make_file(struct __test_metadata * const _metadata,const __u64 access,const mode_t mode,const dev_t dev)1807 static void test_make_file(struct __test_metadata *const _metadata,
1808 const __u64 access, const mode_t mode, const dev_t dev)
1809 {
1810 const struct rule rules[] = {
1811 {
1812 .path = dir_s1d2,
1813 .access = access,
1814 },
1815 {}
1816 };
1817 const int ruleset_fd = create_ruleset(_metadata, access, rules);
1818
1819 ASSERT_LE(0, ruleset_fd);
1820
1821 ASSERT_EQ(0, unlink(file1_s1d1));
1822 ASSERT_EQ(0, unlink(file2_s1d1));
1823 ASSERT_EQ(0, mknod(file2_s1d1, mode | 0400, dev)) {
1824 TH_LOG("Failed to make file \"%s\": %s",
1825 file2_s1d1, strerror(errno));
1826 };
1827
1828 ASSERT_EQ(0, unlink(file1_s1d2));
1829 ASSERT_EQ(0, unlink(file2_s1d2));
1830
1831 ASSERT_EQ(0, unlink(file1_s1d3));
1832 ASSERT_EQ(0, unlink(file2_s1d3));
1833
1834 enforce_ruleset(_metadata, ruleset_fd);
1835 ASSERT_EQ(0, close(ruleset_fd));
1836
1837 ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev));
1838 ASSERT_EQ(EACCES, errno);
1839 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
1840 ASSERT_EQ(EACCES, errno);
1841 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
1842 ASSERT_EQ(EACCES, errno);
1843
1844 ASSERT_EQ(0, mknod(file1_s1d2, mode | 0400, dev)) {
1845 TH_LOG("Failed to make file \"%s\": %s",
1846 file1_s1d2, strerror(errno));
1847 };
1848 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
1849 ASSERT_EQ(0, unlink(file2_s1d2));
1850 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
1851
1852 ASSERT_EQ(0, mknod(file1_s1d3, mode | 0400, dev));
1853 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
1854 ASSERT_EQ(0, unlink(file2_s1d3));
1855 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
1856 }
1857
TEST_F_FORK(layout1,make_char)1858 TEST_F_FORK(layout1, make_char)
1859 {
1860 /* Creates a /dev/null device. */
1861 set_cap(_metadata, CAP_MKNOD);
1862 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR,
1863 makedev(1, 3));
1864 }
1865
TEST_F_FORK(layout1,make_block)1866 TEST_F_FORK(layout1, make_block)
1867 {
1868 /* Creates a /dev/loop0 device. */
1869 set_cap(_metadata, CAP_MKNOD);
1870 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK,
1871 makedev(7, 0));
1872 }
1873
TEST_F_FORK(layout1,make_reg_1)1874 TEST_F_FORK(layout1, make_reg_1)
1875 {
1876 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
1877 }
1878
TEST_F_FORK(layout1,make_reg_2)1879 TEST_F_FORK(layout1, make_reg_2)
1880 {
1881 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
1882 }
1883
TEST_F_FORK(layout1,make_sock)1884 TEST_F_FORK(layout1, make_sock)
1885 {
1886 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
1887 }
1888
TEST_F_FORK(layout1,make_fifo)1889 TEST_F_FORK(layout1, make_fifo)
1890 {
1891 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
1892 }
1893
TEST_F_FORK(layout1,make_sym)1894 TEST_F_FORK(layout1, make_sym)
1895 {
1896 const struct rule rules[] = {
1897 {
1898 .path = dir_s1d2,
1899 .access = LANDLOCK_ACCESS_FS_MAKE_SYM,
1900 },
1901 {}
1902 };
1903 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1904 rules);
1905
1906 ASSERT_LE(0, ruleset_fd);
1907
1908 ASSERT_EQ(0, unlink(file1_s1d1));
1909 ASSERT_EQ(0, unlink(file2_s1d1));
1910 ASSERT_EQ(0, symlink("none", file2_s1d1));
1911
1912 ASSERT_EQ(0, unlink(file1_s1d2));
1913 ASSERT_EQ(0, unlink(file2_s1d2));
1914
1915 ASSERT_EQ(0, unlink(file1_s1d3));
1916 ASSERT_EQ(0, unlink(file2_s1d3));
1917
1918 enforce_ruleset(_metadata, ruleset_fd);
1919 ASSERT_EQ(0, close(ruleset_fd));
1920
1921 ASSERT_EQ(-1, symlink("none", file1_s1d1));
1922 ASSERT_EQ(EACCES, errno);
1923 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
1924 ASSERT_EQ(EACCES, errno);
1925 ASSERT_EQ(-1, rename(file2_s1d1, file1_s1d1));
1926 ASSERT_EQ(EACCES, errno);
1927
1928 ASSERT_EQ(0, symlink("none", file1_s1d2));
1929 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
1930 ASSERT_EQ(0, unlink(file2_s1d2));
1931 ASSERT_EQ(0, rename(file1_s1d2, file2_s1d2));
1932
1933 ASSERT_EQ(0, symlink("none", file1_s1d3));
1934 ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
1935 ASSERT_EQ(0, unlink(file2_s1d3));
1936 ASSERT_EQ(0, rename(file1_s1d3, file2_s1d3));
1937 }
1938
TEST_F_FORK(layout1,make_dir)1939 TEST_F_FORK(layout1, make_dir)
1940 {
1941 const struct rule rules[] = {
1942 {
1943 .path = dir_s1d2,
1944 .access = LANDLOCK_ACCESS_FS_MAKE_DIR,
1945 },
1946 {}
1947 };
1948 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
1949 rules);
1950
1951 ASSERT_LE(0, ruleset_fd);
1952
1953 ASSERT_EQ(0, unlink(file1_s1d1));
1954 ASSERT_EQ(0, unlink(file1_s1d2));
1955 ASSERT_EQ(0, unlink(file1_s1d3));
1956
1957 enforce_ruleset(_metadata, ruleset_fd);
1958 ASSERT_EQ(0, close(ruleset_fd));
1959
1960 /* Uses file_* as directory names. */
1961 ASSERT_EQ(-1, mkdir(file1_s1d1, 0700));
1962 ASSERT_EQ(EACCES, errno);
1963 ASSERT_EQ(0, mkdir(file1_s1d2, 0700));
1964 ASSERT_EQ(0, mkdir(file1_s1d3, 0700));
1965 }
1966
open_proc_fd(struct __test_metadata * const _metadata,const int fd,const int open_flags)1967 static int open_proc_fd(struct __test_metadata *const _metadata, const int fd,
1968 const int open_flags)
1969 {
1970 static const char path_template[] = "/proc/self/fd/%d";
1971 char procfd_path[sizeof(path_template) + 10];
1972 const int procfd_path_size = snprintf(procfd_path, sizeof(procfd_path),
1973 path_template, fd);
1974
1975 ASSERT_LT(procfd_path_size, sizeof(procfd_path));
1976 return open(procfd_path, open_flags);
1977 }
1978
TEST_F_FORK(layout1,proc_unlinked_file)1979 TEST_F_FORK(layout1, proc_unlinked_file)
1980 {
1981 const struct rule rules[] = {
1982 {
1983 .path = file1_s1d2,
1984 .access = LANDLOCK_ACCESS_FS_READ_FILE,
1985 },
1986 {}
1987 };
1988 int reg_fd, proc_fd;
1989 const int ruleset_fd = create_ruleset(_metadata,
1990 LANDLOCK_ACCESS_FS_READ_FILE |
1991 LANDLOCK_ACCESS_FS_WRITE_FILE, rules);
1992
1993 ASSERT_LE(0, ruleset_fd);
1994 enforce_ruleset(_metadata, ruleset_fd);
1995 ASSERT_EQ(0, close(ruleset_fd));
1996
1997 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR));
1998 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
1999 reg_fd = open(file1_s1d2, O_RDONLY | O_CLOEXEC);
2000 ASSERT_LE(0, reg_fd);
2001 ASSERT_EQ(0, unlink(file1_s1d2));
2002
2003 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDONLY | O_CLOEXEC);
2004 ASSERT_LE(0, proc_fd);
2005 ASSERT_EQ(0, close(proc_fd));
2006
2007 proc_fd = open_proc_fd(_metadata, reg_fd, O_RDWR | O_CLOEXEC);
2008 ASSERT_EQ(-1, proc_fd) {
2009 TH_LOG("Successfully opened /proc/self/fd/%d: %s",
2010 reg_fd, strerror(errno));
2011 }
2012 ASSERT_EQ(EACCES, errno);
2013
2014 ASSERT_EQ(0, close(reg_fd));
2015 }
2016
TEST_F_FORK(layout1,proc_pipe)2017 TEST_F_FORK(layout1, proc_pipe)
2018 {
2019 int proc_fd;
2020 int pipe_fds[2];
2021 char buf = '\0';
2022 const struct rule rules[] = {
2023 {
2024 .path = dir_s1d2,
2025 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2026 LANDLOCK_ACCESS_FS_WRITE_FILE,
2027 },
2028 {}
2029 };
2030 /* Limits read and write access to files tied to the filesystem. */
2031 const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
2032 rules);
2033
2034 ASSERT_LE(0, ruleset_fd);
2035 enforce_ruleset(_metadata, ruleset_fd);
2036 ASSERT_EQ(0, close(ruleset_fd));
2037
2038 /* Checks enforcement for normal files. */
2039 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
2040 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
2041
2042 /* Checks access to pipes through FD. */
2043 ASSERT_EQ(0, pipe2(pipe_fds, O_CLOEXEC));
2044 ASSERT_EQ(1, write(pipe_fds[1], ".", 1)) {
2045 TH_LOG("Failed to write in pipe: %s", strerror(errno));
2046 }
2047 ASSERT_EQ(1, read(pipe_fds[0], &buf, 1));
2048 ASSERT_EQ('.', buf);
2049
2050 /* Checks write access to pipe through /proc/self/fd . */
2051 proc_fd = open_proc_fd(_metadata, pipe_fds[1], O_WRONLY | O_CLOEXEC);
2052 ASSERT_LE(0, proc_fd);
2053 ASSERT_EQ(1, write(proc_fd, ".", 1)) {
2054 TH_LOG("Failed to write through /proc/self/fd/%d: %s",
2055 pipe_fds[1], strerror(errno));
2056 }
2057 ASSERT_EQ(0, close(proc_fd));
2058
2059 /* Checks read access to pipe through /proc/self/fd . */
2060 proc_fd = open_proc_fd(_metadata, pipe_fds[0], O_RDONLY | O_CLOEXEC);
2061 ASSERT_LE(0, proc_fd);
2062 buf = '\0';
2063 ASSERT_EQ(1, read(proc_fd, &buf, 1)) {
2064 TH_LOG("Failed to read through /proc/self/fd/%d: %s",
2065 pipe_fds[1], strerror(errno));
2066 }
2067 ASSERT_EQ(0, close(proc_fd));
2068
2069 ASSERT_EQ(0, close(pipe_fds[0]));
2070 ASSERT_EQ(0, close(pipe_fds[1]));
2071 }
2072
FIXTURE(layout1_bind)2073 FIXTURE(layout1_bind) {
2074 };
2075
FIXTURE_SETUP(layout1_bind)2076 FIXTURE_SETUP(layout1_bind)
2077 {
2078 prepare_layout(_metadata);
2079
2080 create_layout1(_metadata);
2081
2082 set_cap(_metadata, CAP_SYS_ADMIN);
2083 ASSERT_EQ(0, mount(dir_s1d2, dir_s2d2, NULL, MS_BIND, NULL));
2084 clear_cap(_metadata, CAP_SYS_ADMIN);
2085 }
2086
FIXTURE_TEARDOWN(layout1_bind)2087 FIXTURE_TEARDOWN(layout1_bind)
2088 {
2089 set_cap(_metadata, CAP_SYS_ADMIN);
2090 EXPECT_EQ(0, umount(dir_s2d2));
2091 clear_cap(_metadata, CAP_SYS_ADMIN);
2092
2093 remove_layout1(_metadata);
2094
2095 cleanup_layout(_metadata);
2096 }
2097
2098 static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
2099 static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
2100
2101 /*
2102 * layout1_bind hierarchy:
2103 *
2104 * tmp
2105 * ├── s1d1
2106 * │ ├── f1
2107 * │ ├── f2
2108 * │ └── s1d2
2109 * │ ├── f1
2110 * │ ├── f2
2111 * │ └── s1d3
2112 * │ ├── f1
2113 * │ └── f2
2114 * ├── s2d1
2115 * │ ├── f1
2116 * │ └── s2d2
2117 * │ ├── f1
2118 * │ ├── f2
2119 * │ └── s1d3
2120 * │ ├── f1
2121 * │ └── f2
2122 * └── s3d1
2123 * └── s3d2
2124 * └── s3d3
2125 */
2126
TEST_F_FORK(layout1_bind,no_restriction)2127 TEST_F_FORK(layout1_bind, no_restriction)
2128 {
2129 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY));
2130 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
2131 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY));
2132 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
2133 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
2134 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
2135
2136 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY));
2137 ASSERT_EQ(0, test_open(file1_s2d1, O_RDONLY));
2138 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY));
2139 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
2140 ASSERT_EQ(ENOENT, test_open(dir_s2d3, O_RDONLY));
2141 ASSERT_EQ(ENOENT, test_open(file1_s2d3, O_RDONLY));
2142
2143 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY));
2144 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
2145
2146 ASSERT_EQ(0, test_open(dir_s3d1, O_RDONLY));
2147 }
2148
TEST_F_FORK(layout1_bind,same_content_same_file)2149 TEST_F_FORK(layout1_bind, same_content_same_file)
2150 {
2151 /*
2152 * Sets access right on parent directories of both source and
2153 * destination mount points.
2154 */
2155 const struct rule layer1_parent[] = {
2156 {
2157 .path = dir_s1d1,
2158 .access = ACCESS_RO,
2159 },
2160 {
2161 .path = dir_s2d1,
2162 .access = ACCESS_RW,
2163 },
2164 {}
2165 };
2166 /*
2167 * Sets access rights on the same bind-mounted directories. The result
2168 * should be ACCESS_RW for both directories, but not both hierarchies
2169 * because of the first layer.
2170 */
2171 const struct rule layer2_mount_point[] = {
2172 {
2173 .path = dir_s1d2,
2174 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2175 },
2176 {
2177 .path = dir_s2d2,
2178 .access = ACCESS_RW,
2179 },
2180 {}
2181 };
2182 /* Only allow read-access to the s1d3 hierarchies. */
2183 const struct rule layer3_source[] = {
2184 {
2185 .path = dir_s1d3,
2186 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2187 },
2188 {}
2189 };
2190 /* Removes all access rights. */
2191 const struct rule layer4_destination[] = {
2192 {
2193 .path = bind_file1_s1d3,
2194 .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
2195 },
2196 {}
2197 };
2198 int ruleset_fd;
2199
2200 /* Sets rules for the parent directories. */
2201 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent);
2202 ASSERT_LE(0, ruleset_fd);
2203 enforce_ruleset(_metadata, ruleset_fd);
2204 ASSERT_EQ(0, close(ruleset_fd));
2205
2206 /* Checks source hierarchy. */
2207 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY));
2208 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
2209 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
2210
2211 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
2212 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
2213 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
2214
2215 /* Checks destination hierarchy. */
2216 ASSERT_EQ(0, test_open(file1_s2d1, O_RDWR));
2217 ASSERT_EQ(0, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
2218
2219 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
2220 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
2221
2222 /* Sets rules for the mount points. */
2223 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point);
2224 ASSERT_LE(0, ruleset_fd);
2225 enforce_ruleset(_metadata, ruleset_fd);
2226 ASSERT_EQ(0, close(ruleset_fd));
2227
2228 /* Checks source hierarchy. */
2229 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY));
2230 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
2231 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
2232
2233 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY));
2234 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
2235 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
2236
2237 /* Checks destination hierarchy. */
2238 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_RDONLY));
2239 ASSERT_EQ(EACCES, test_open(file1_s2d1, O_WRONLY));
2240 ASSERT_EQ(EACCES, test_open(dir_s2d1, O_RDONLY | O_DIRECTORY));
2241
2242 ASSERT_EQ(0, test_open(file1_s2d2, O_RDWR));
2243 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
2244 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
2245
2246 /* Sets a (shared) rule only on the source. */
2247 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source);
2248 ASSERT_LE(0, ruleset_fd);
2249 enforce_ruleset(_metadata, ruleset_fd);
2250 ASSERT_EQ(0, close(ruleset_fd));
2251
2252 /* Checks source hierarchy. */
2253 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY));
2254 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
2255 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
2256
2257 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
2258 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
2259 ASSERT_EQ(EACCES, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
2260
2261 /* Checks destination hierarchy. */
2262 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_RDONLY));
2263 ASSERT_EQ(EACCES, test_open(file1_s2d2, O_WRONLY));
2264 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY));
2265
2266 ASSERT_EQ(0, test_open(bind_file1_s1d3, O_RDONLY));
2267 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
2268 ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY));
2269
2270 /* Sets a (shared) rule only on the destination. */
2271 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination);
2272 ASSERT_LE(0, ruleset_fd);
2273 enforce_ruleset(_metadata, ruleset_fd);
2274 ASSERT_EQ(0, close(ruleset_fd));
2275
2276 /* Checks source hierarchy. */
2277 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
2278 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
2279
2280 /* Checks destination hierarchy. */
2281 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_RDONLY));
2282 ASSERT_EQ(EACCES, test_open(bind_file1_s1d3, O_WRONLY));
2283 }
2284
2285 #define LOWER_BASE TMP_DIR "/lower"
2286 #define LOWER_DATA LOWER_BASE "/data"
2287 static const char lower_fl1[] = LOWER_DATA "/fl1";
2288 static const char lower_dl1[] = LOWER_DATA "/dl1";
2289 static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
2290 static const char lower_fo1[] = LOWER_DATA "/fo1";
2291 static const char lower_do1[] = LOWER_DATA "/do1";
2292 static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
2293 static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
2294
2295 static const char (*lower_base_files[])[] = {
2296 &lower_fl1,
2297 &lower_fo1,
2298 NULL
2299 };
2300 static const char (*lower_base_directories[])[] = {
2301 &lower_dl1,
2302 &lower_do1,
2303 NULL
2304 };
2305 static const char (*lower_sub_files[])[] = {
2306 &lower_dl1_fl2,
2307 &lower_do1_fo2,
2308 &lower_do1_fl3,
2309 NULL
2310 };
2311
2312 #define UPPER_BASE TMP_DIR "/upper"
2313 #define UPPER_DATA UPPER_BASE "/data"
2314 #define UPPER_WORK UPPER_BASE "/work"
2315 static const char upper_fu1[] = UPPER_DATA "/fu1";
2316 static const char upper_du1[] = UPPER_DATA "/du1";
2317 static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
2318 static const char upper_fo1[] = UPPER_DATA "/fo1";
2319 static const char upper_do1[] = UPPER_DATA "/do1";
2320 static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
2321 static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
2322
2323 static const char (*upper_base_files[])[] = {
2324 &upper_fu1,
2325 &upper_fo1,
2326 NULL
2327 };
2328 static const char (*upper_base_directories[])[] = {
2329 &upper_du1,
2330 &upper_do1,
2331 NULL
2332 };
2333 static const char (*upper_sub_files[])[] = {
2334 &upper_du1_fu2,
2335 &upper_do1_fo2,
2336 &upper_do1_fu3,
2337 NULL
2338 };
2339
2340 #define MERGE_BASE TMP_DIR "/merge"
2341 #define MERGE_DATA MERGE_BASE "/data"
2342 static const char merge_fl1[] = MERGE_DATA "/fl1";
2343 static const char merge_dl1[] = MERGE_DATA "/dl1";
2344 static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
2345 static const char merge_fu1[] = MERGE_DATA "/fu1";
2346 static const char merge_du1[] = MERGE_DATA "/du1";
2347 static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
2348 static const char merge_fo1[] = MERGE_DATA "/fo1";
2349 static const char merge_do1[] = MERGE_DATA "/do1";
2350 static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
2351 static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
2352 static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
2353
2354 static const char (*merge_base_files[])[] = {
2355 &merge_fl1,
2356 &merge_fu1,
2357 &merge_fo1,
2358 NULL
2359 };
2360 static const char (*merge_base_directories[])[] = {
2361 &merge_dl1,
2362 &merge_du1,
2363 &merge_do1,
2364 NULL
2365 };
2366 static const char (*merge_sub_files[])[] = {
2367 &merge_dl1_fl2,
2368 &merge_du1_fu2,
2369 &merge_do1_fo2,
2370 &merge_do1_fl3,
2371 &merge_do1_fu3,
2372 NULL
2373 };
2374
2375 /*
2376 * layout2_overlay hierarchy:
2377 *
2378 * tmp
2379 * ├── lower
2380 * │ └── data
2381 * │ ├── dl1
2382 * │ │ └── fl2
2383 * │ ├── do1
2384 * │ │ ├── fl3
2385 * │ │ └── fo2
2386 * │ ├── fl1
2387 * │ └── fo1
2388 * ├── merge
2389 * │ └── data
2390 * │ ├── dl1
2391 * │ │ └── fl2
2392 * │ ├── do1
2393 * │ │ ├── fl3
2394 * │ │ ├── fo2
2395 * │ │ └── fu3
2396 * │ ├── du1
2397 * │ │ └── fu2
2398 * │ ├── fl1
2399 * │ ├── fo1
2400 * │ └── fu1
2401 * └── upper
2402 * ├── data
2403 * │ ├── do1
2404 * │ │ ├── fo2
2405 * │ │ └── fu3
2406 * │ ├── du1
2407 * │ │ └── fu2
2408 * │ ├── fo1
2409 * │ └── fu1
2410 * └── work
2411 * └── work
2412 */
2413
FIXTURE(layout2_overlay)2414 FIXTURE(layout2_overlay) {
2415 };
2416
FIXTURE_SETUP(layout2_overlay)2417 FIXTURE_SETUP(layout2_overlay)
2418 {
2419 prepare_layout(_metadata);
2420
2421 create_directory(_metadata, LOWER_BASE);
2422 set_cap(_metadata, CAP_SYS_ADMIN);
2423 /* Creates tmpfs mount points to get deterministic overlayfs. */
2424 ASSERT_EQ(0, mount("tmp", LOWER_BASE, "tmpfs", 0, "size=4m,mode=700"));
2425 clear_cap(_metadata, CAP_SYS_ADMIN);
2426 create_file(_metadata, lower_fl1);
2427 create_file(_metadata, lower_dl1_fl2);
2428 create_file(_metadata, lower_fo1);
2429 create_file(_metadata, lower_do1_fo2);
2430 create_file(_metadata, lower_do1_fl3);
2431
2432 create_directory(_metadata, UPPER_BASE);
2433 set_cap(_metadata, CAP_SYS_ADMIN);
2434 ASSERT_EQ(0, mount("tmp", UPPER_BASE, "tmpfs", 0, "size=4m,mode=700"));
2435 clear_cap(_metadata, CAP_SYS_ADMIN);
2436 create_file(_metadata, upper_fu1);
2437 create_file(_metadata, upper_du1_fu2);
2438 create_file(_metadata, upper_fo1);
2439 create_file(_metadata, upper_do1_fo2);
2440 create_file(_metadata, upper_do1_fu3);
2441 ASSERT_EQ(0, mkdir(UPPER_WORK, 0700));
2442
2443 create_directory(_metadata, MERGE_DATA);
2444 set_cap(_metadata, CAP_SYS_ADMIN);
2445 set_cap(_metadata, CAP_DAC_OVERRIDE);
2446 ASSERT_EQ(0, mount("overlay", MERGE_DATA, "overlay", 0,
2447 "lowerdir=" LOWER_DATA
2448 ",upperdir=" UPPER_DATA
2449 ",workdir=" UPPER_WORK));
2450 clear_cap(_metadata, CAP_DAC_OVERRIDE);
2451 clear_cap(_metadata, CAP_SYS_ADMIN);
2452 }
2453
FIXTURE_TEARDOWN(layout2_overlay)2454 FIXTURE_TEARDOWN(layout2_overlay)
2455 {
2456 EXPECT_EQ(0, remove_path(lower_do1_fl3));
2457 EXPECT_EQ(0, remove_path(lower_dl1_fl2));
2458 EXPECT_EQ(0, remove_path(lower_fl1));
2459 EXPECT_EQ(0, remove_path(lower_do1_fo2));
2460 EXPECT_EQ(0, remove_path(lower_fo1));
2461 set_cap(_metadata, CAP_SYS_ADMIN);
2462 EXPECT_EQ(0, umount(LOWER_BASE));
2463 clear_cap(_metadata, CAP_SYS_ADMIN);
2464 EXPECT_EQ(0, remove_path(LOWER_BASE));
2465
2466 EXPECT_EQ(0, remove_path(upper_do1_fu3));
2467 EXPECT_EQ(0, remove_path(upper_du1_fu2));
2468 EXPECT_EQ(0, remove_path(upper_fu1));
2469 EXPECT_EQ(0, remove_path(upper_do1_fo2));
2470 EXPECT_EQ(0, remove_path(upper_fo1));
2471 EXPECT_EQ(0, remove_path(UPPER_WORK "/work"));
2472 set_cap(_metadata, CAP_SYS_ADMIN);
2473 EXPECT_EQ(0, umount(UPPER_BASE));
2474 clear_cap(_metadata, CAP_SYS_ADMIN);
2475 EXPECT_EQ(0, remove_path(UPPER_BASE));
2476
2477 set_cap(_metadata, CAP_SYS_ADMIN);
2478 EXPECT_EQ(0, umount(MERGE_DATA));
2479 clear_cap(_metadata, CAP_SYS_ADMIN);
2480 EXPECT_EQ(0, remove_path(MERGE_DATA));
2481
2482 cleanup_layout(_metadata);
2483 }
2484
TEST_F_FORK(layout2_overlay,no_restriction)2485 TEST_F_FORK(layout2_overlay, no_restriction)
2486 {
2487 ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
2488 ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
2489 ASSERT_EQ(0, test_open(lower_dl1_fl2, O_RDONLY));
2490 ASSERT_EQ(0, test_open(lower_fo1, O_RDONLY));
2491 ASSERT_EQ(0, test_open(lower_do1, O_RDONLY));
2492 ASSERT_EQ(0, test_open(lower_do1_fo2, O_RDONLY));
2493 ASSERT_EQ(0, test_open(lower_do1_fl3, O_RDONLY));
2494
2495 ASSERT_EQ(0, test_open(upper_fu1, O_RDONLY));
2496 ASSERT_EQ(0, test_open(upper_du1, O_RDONLY));
2497 ASSERT_EQ(0, test_open(upper_du1_fu2, O_RDONLY));
2498 ASSERT_EQ(0, test_open(upper_fo1, O_RDONLY));
2499 ASSERT_EQ(0, test_open(upper_do1, O_RDONLY));
2500 ASSERT_EQ(0, test_open(upper_do1_fo2, O_RDONLY));
2501 ASSERT_EQ(0, test_open(upper_do1_fu3, O_RDONLY));
2502
2503 ASSERT_EQ(0, test_open(merge_fl1, O_RDONLY));
2504 ASSERT_EQ(0, test_open(merge_dl1, O_RDONLY));
2505 ASSERT_EQ(0, test_open(merge_dl1_fl2, O_RDONLY));
2506 ASSERT_EQ(0, test_open(merge_fu1, O_RDONLY));
2507 ASSERT_EQ(0, test_open(merge_du1, O_RDONLY));
2508 ASSERT_EQ(0, test_open(merge_du1_fu2, O_RDONLY));
2509 ASSERT_EQ(0, test_open(merge_fo1, O_RDONLY));
2510 ASSERT_EQ(0, test_open(merge_do1, O_RDONLY));
2511 ASSERT_EQ(0, test_open(merge_do1_fo2, O_RDONLY));
2512 ASSERT_EQ(0, test_open(merge_do1_fl3, O_RDONLY));
2513 ASSERT_EQ(0, test_open(merge_do1_fu3, O_RDONLY));
2514 }
2515
2516 #define for_each_path(path_list, path_entry, i) \
2517 for (i = 0, path_entry = *path_list[i]; path_list[i]; \
2518 path_entry = *path_list[++i])
2519
TEST_F_FORK(layout2_overlay,same_content_different_file)2520 TEST_F_FORK(layout2_overlay, same_content_different_file)
2521 {
2522 /* Sets access right on parent directories of both layers. */
2523 const struct rule layer1_base[] = {
2524 {
2525 .path = LOWER_BASE,
2526 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2527 },
2528 {
2529 .path = UPPER_BASE,
2530 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2531 },
2532 {
2533 .path = MERGE_BASE,
2534 .access = ACCESS_RW,
2535 },
2536 {}
2537 };
2538 const struct rule layer2_data[] = {
2539 {
2540 .path = LOWER_DATA,
2541 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2542 },
2543 {
2544 .path = UPPER_DATA,
2545 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2546 },
2547 {
2548 .path = MERGE_DATA,
2549 .access = ACCESS_RW,
2550 },
2551 {}
2552 };
2553 /* Sets access right on directories inside both layers. */
2554 const struct rule layer3_subdirs[] = {
2555 {
2556 .path = lower_dl1,
2557 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2558 },
2559 {
2560 .path = lower_do1,
2561 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2562 },
2563 {
2564 .path = upper_du1,
2565 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2566 },
2567 {
2568 .path = upper_do1,
2569 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2570 },
2571 {
2572 .path = merge_dl1,
2573 .access = ACCESS_RW,
2574 },
2575 {
2576 .path = merge_du1,
2577 .access = ACCESS_RW,
2578 },
2579 {
2580 .path = merge_do1,
2581 .access = ACCESS_RW,
2582 },
2583 {}
2584 };
2585 /* Tighten access rights to the files. */
2586 const struct rule layer4_files[] = {
2587 {
2588 .path = lower_dl1_fl2,
2589 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2590 },
2591 {
2592 .path = lower_do1_fo2,
2593 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2594 },
2595 {
2596 .path = lower_do1_fl3,
2597 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2598 },
2599 {
2600 .path = upper_du1_fu2,
2601 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2602 },
2603 {
2604 .path = upper_do1_fo2,
2605 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2606 },
2607 {
2608 .path = upper_do1_fu3,
2609 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2610 },
2611 {
2612 .path = merge_dl1_fl2,
2613 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2614 LANDLOCK_ACCESS_FS_WRITE_FILE,
2615 },
2616 {
2617 .path = merge_du1_fu2,
2618 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2619 LANDLOCK_ACCESS_FS_WRITE_FILE,
2620 },
2621 {
2622 .path = merge_do1_fo2,
2623 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2624 LANDLOCK_ACCESS_FS_WRITE_FILE,
2625 },
2626 {
2627 .path = merge_do1_fl3,
2628 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2629 LANDLOCK_ACCESS_FS_WRITE_FILE,
2630 },
2631 {
2632 .path = merge_do1_fu3,
2633 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2634 LANDLOCK_ACCESS_FS_WRITE_FILE,
2635 },
2636 {}
2637 };
2638 const struct rule layer5_merge_only[] = {
2639 {
2640 .path = MERGE_DATA,
2641 .access = LANDLOCK_ACCESS_FS_READ_FILE |
2642 LANDLOCK_ACCESS_FS_WRITE_FILE,
2643 },
2644 {}
2645 };
2646 int ruleset_fd;
2647 size_t i;
2648 const char *path_entry;
2649
2650 /* Sets rules on base directories (i.e. outside overlay scope). */
2651 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
2652 ASSERT_LE(0, ruleset_fd);
2653 enforce_ruleset(_metadata, ruleset_fd);
2654 ASSERT_EQ(0, close(ruleset_fd));
2655
2656 /* Checks lower layer. */
2657 for_each_path(lower_base_files, path_entry, i) {
2658 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2659 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2660 }
2661 for_each_path(lower_base_directories, path_entry, i) {
2662 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2663 }
2664 for_each_path(lower_sub_files, path_entry, i) {
2665 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2666 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2667 }
2668 /* Checks upper layer. */
2669 for_each_path(upper_base_files, path_entry, i) {
2670 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2671 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2672 }
2673 for_each_path(upper_base_directories, path_entry, i) {
2674 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2675 }
2676 for_each_path(upper_sub_files, path_entry, i) {
2677 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2678 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2679 }
2680 /*
2681 * Checks that access rights are independent from the lower and upper
2682 * layers: write access to upper files viewed through the merge point
2683 * is still allowed, and write access to lower file viewed (and copied)
2684 * through the merge point is still allowed.
2685 */
2686 for_each_path(merge_base_files, path_entry, i) {
2687 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2688 }
2689 for_each_path(merge_base_directories, path_entry, i) {
2690 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2691 }
2692 for_each_path(merge_sub_files, path_entry, i) {
2693 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2694 }
2695
2696 /* Sets rules on data directories (i.e. inside overlay scope). */
2697 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data);
2698 ASSERT_LE(0, ruleset_fd);
2699 enforce_ruleset(_metadata, ruleset_fd);
2700 ASSERT_EQ(0, close(ruleset_fd));
2701
2702 /* Checks merge. */
2703 for_each_path(merge_base_files, path_entry, i) {
2704 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2705 }
2706 for_each_path(merge_base_directories, path_entry, i) {
2707 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2708 }
2709 for_each_path(merge_sub_files, path_entry, i) {
2710 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2711 }
2712
2713 /* Same checks with tighter rules. */
2714 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs);
2715 ASSERT_LE(0, ruleset_fd);
2716 enforce_ruleset(_metadata, ruleset_fd);
2717 ASSERT_EQ(0, close(ruleset_fd));
2718
2719 /* Checks changes for lower layer. */
2720 for_each_path(lower_base_files, path_entry, i) {
2721 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2722 }
2723 /* Checks changes for upper layer. */
2724 for_each_path(upper_base_files, path_entry, i) {
2725 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2726 }
2727 /* Checks all merge accesses. */
2728 for_each_path(merge_base_files, path_entry, i) {
2729 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
2730 }
2731 for_each_path(merge_base_directories, path_entry, i) {
2732 ASSERT_EQ(0, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2733 }
2734 for_each_path(merge_sub_files, path_entry, i) {
2735 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2736 }
2737
2738 /* Sets rules directly on overlayed files. */
2739 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files);
2740 ASSERT_LE(0, ruleset_fd);
2741 enforce_ruleset(_metadata, ruleset_fd);
2742 ASSERT_EQ(0, close(ruleset_fd));
2743
2744 /* Checks unchanged accesses on lower layer. */
2745 for_each_path(lower_sub_files, path_entry, i) {
2746 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2747 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2748 }
2749 /* Checks unchanged accesses on upper layer. */
2750 for_each_path(upper_sub_files, path_entry, i) {
2751 ASSERT_EQ(0, test_open(path_entry, O_RDONLY));
2752 ASSERT_EQ(EACCES, test_open(path_entry, O_WRONLY));
2753 }
2754 /* Checks all merge accesses. */
2755 for_each_path(merge_base_files, path_entry, i) {
2756 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
2757 }
2758 for_each_path(merge_base_directories, path_entry, i) {
2759 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2760 }
2761 for_each_path(merge_sub_files, path_entry, i) {
2762 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2763 }
2764
2765 /* Only allowes access to the merge hierarchy. */
2766 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only);
2767 ASSERT_LE(0, ruleset_fd);
2768 enforce_ruleset(_metadata, ruleset_fd);
2769 ASSERT_EQ(0, close(ruleset_fd));
2770
2771 /* Checks new accesses on lower layer. */
2772 for_each_path(lower_sub_files, path_entry, i) {
2773 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2774 }
2775 /* Checks new accesses on upper layer. */
2776 for_each_path(upper_sub_files, path_entry, i) {
2777 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2778 }
2779 /* Checks all merge accesses. */
2780 for_each_path(merge_base_files, path_entry, i) {
2781 ASSERT_EQ(EACCES, test_open(path_entry, O_RDWR));
2782 }
2783 for_each_path(merge_base_directories, path_entry, i) {
2784 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY | O_DIRECTORY));
2785 }
2786 for_each_path(merge_sub_files, path_entry, i) {
2787 ASSERT_EQ(0, test_open(path_entry, O_RDWR));
2788 }
2789 }
2790
2791 TEST_HARNESS_MAIN
2792