1
2
3
4
5
6
7
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
29static const char dir_s1d1[] = TMP_DIR "/s1d1";
30static const char file1_s1d1[] = TMP_DIR "/s1d1/f1";
31static const char file2_s1d1[] = TMP_DIR "/s1d1/f2";
32static const char dir_s1d2[] = TMP_DIR "/s1d1/s1d2";
33static const char file1_s1d2[] = TMP_DIR "/s1d1/s1d2/f1";
34static const char file2_s1d2[] = TMP_DIR "/s1d1/s1d2/f2";
35static const char dir_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3";
36static const char file1_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f1";
37static const char file2_s1d3[] = TMP_DIR "/s1d1/s1d2/s1d3/f2";
38
39static const char dir_s2d1[] = TMP_DIR "/s2d1";
40static const char file1_s2d1[] = TMP_DIR "/s2d1/f1";
41static const char dir_s2d2[] = TMP_DIR "/s2d1/s2d2";
42static const char file1_s2d2[] = TMP_DIR "/s2d1/s2d2/f1";
43static const char dir_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3";
44static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1";
45static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2";
46
47static const char dir_s3d1[] = TMP_DIR "/s3d1";
48
49static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2";
50static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3";
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77static 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
102static 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
112static 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
122static 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
151out:
152 free(walker);
153 return err;
154}
155
156static 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
164
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
173static 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
181static 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
203static 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
224FIXTURE(layout1) {
225};
226
227FIXTURE_SETUP(layout1)
228{
229 prepare_layout(_metadata);
230
231 create_layout1(_metadata);
232}
233
234FIXTURE_TEARDOWN(layout1)
235{
236 remove_layout1(_metadata);
237
238 cleanup_layout(_metadata);
239}
240
241
242
243
244
245static int test_open_rel(const int dirfd, const char *const path, const int flags)
246{
247 int fd;
248
249
250 fd = openat(dirfd, path, flags | O_CLOEXEC);
251 if (fd < 0)
252 return errno;
253
254
255
256
257 if (close(fd) != 0)
258 return errno;
259 return 0;
260}
261
262static int test_open(const char *const path, const int flags)
263{
264 return test_open_rel(AT_FDCWD, path, flags);
265}
266
267TEST_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
290TEST_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
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
320 ASSERT_EQ(EBADFD, errno);
321 ASSERT_EQ(0, close(ruleset_fd));
322
323
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
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
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
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
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
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
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
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
399TEST_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
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
429static 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
450struct 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
463static 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
491static 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
500TEST_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
529
530
531
532 ASSERT_EQ(0, test_open("/proc/self/ns/mnt", O_RDONLY));
533
534
535
536
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
548TEST_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
566 enforce_ruleset(_metadata, ruleset_fd);
567 ASSERT_EQ(0, close(ruleset_fd));
568}
569
570TEST_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
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
602 ASSERT_EQ(EACCES, test_open(dir_s2d2, O_RDONLY));
603 ASSERT_EQ(0, test_open(file1_s2d2, O_RDONLY));
604
605
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
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
622TEST_F_FORK(layout1, unhandled_access)
623{
624 const struct rule rules[] = {
625 {
626 .path = dir_s1d2,
627 .access = ACCESS_RO,
628 },
629 {}
630 };
631
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
640
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
649TEST_F_FORK(layout1, ruleset_overlap)
650{
651 const struct rule rules[] = {
652
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
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
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
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
690TEST_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
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
734 ASSERT_EQ(-1, unlink(file1_s1d2));
735 ASSERT_EQ(EACCES, errno);
736 ASSERT_EQ(0, unlink(file1_s1d3));
737}
738
739TEST_F_FORK(layout1, interleaved_masked_accesses)
740{
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755 const struct rule layer1_read[] = {
756
757 {
758 .path = file1_s1d3,
759 .access = LANDLOCK_ACCESS_FS_READ_FILE,
760 },
761 {}
762 };
763
764 const struct rule layer2_read_write[] = {
765
766 {
767 .path = dir_s1d3,
768 .access = LANDLOCK_ACCESS_FS_READ_FILE |
769 LANDLOCK_ACCESS_FS_WRITE_FILE,
770 },
771
772 {
773 .path = dir_s1d2,
774 .access = LANDLOCK_ACCESS_FS_WRITE_FILE,
775 },
776 {}
777 };
778 const struct rule layer3_read[] = {
779
780 {
781 .path = dir_s1d1,
782 .access = LANDLOCK_ACCESS_FS_READ_FILE,
783 },
784 {}
785 };
786 const struct rule layer4_read_write[] = {
787
788
789
790
791 {
792 .path = dir_s1d2,
793 .access = LANDLOCK_ACCESS_FS_READ_FILE,
794 },
795 {}
796 };
797 const struct rule layer5_read[] = {
798
799
800
801
802 {
803 .path = dir_s1d2,
804 .access = LANDLOCK_ACCESS_FS_READ_FILE,
805 },
806 {}
807 };
808 const struct rule layer6_execute[] = {
809
810
811
812
813 {
814 .path = dir_s2d1,
815 .access = LANDLOCK_ACCESS_FS_EXECUTE,
816 },
817 {}
818 };
819 const struct rule layer7_read_write[] = {
820
821
822
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
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
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
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
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
874
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
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
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
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
918TEST_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
937 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
938
939 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
940
941
942 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
943
944 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
945
946
947
948
949
950
951 add_path_beneath(_metadata, ruleset_fd, LANDLOCK_ACCESS_FS_WRITE_FILE,
952 dir_s1d2);
953
954
955
956
957
958
959
960
961
962
963
964 enforce_ruleset(_metadata, ruleset_fd);
965
966
967 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
968 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
969
970
971 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
972
973 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
974
975
976 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
977
978 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
979
980
981
982
983
984 add_path_beneath(_metadata, ruleset_fd, ACCESS_RW, dir_s1d1);
985 enforce_ruleset(_metadata, ruleset_fd);
986
987
988 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
989 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
990
991
992 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
993
994 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
995
996
997 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
998
999 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1000
1001
1002
1003
1004
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
1013
1014
1015
1016
1017
1018 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY));
1019 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY));
1020
1021
1022 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_WRONLY));
1023
1024 ASSERT_EQ(0, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1025
1026
1027 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
1028
1029
1030
1031
1032 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1033}
1034
1035TEST_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
1050 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1051
1052 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1053
1054 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1055
1056
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
1063 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY));
1064
1065 ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY | O_DIRECTORY));
1066
1067 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
1068}
1069
1070TEST_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
1094TEST_F_FORK(layout1, empty_or_same_ruleset)
1095{
1096 struct landlock_ruleset_attr ruleset_attr = {};
1097 int ruleset_fd;
1098
1099
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
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
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
1124 enforce_ruleset(_metadata, ruleset_fd);
1125 ASSERT_EQ(0, close(ruleset_fd));
1126}
1127
1128TEST_F_FORK(layout1, rule_on_mountpoint)
1129{
1130 const struct rule rules[] = {
1131 {
1132 .path = dir_s1d1,
1133 .access = ACCESS_RO,
1134 },
1135 {
1136
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
1157TEST_F_FORK(layout1, rule_over_mountpoint)
1158{
1159 const struct rule rules[] = {
1160 {
1161 .path = dir_s1d1,
1162 .access = ACCESS_RO,
1163 },
1164 {
1165
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
1188
1189
1190TEST_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
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
1216 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1217 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1218}
1219
1220TEST_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
1236 ASSERT_EQ(EACCES, test_open("/", O_RDONLY));
1237 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY));
1238}
1239
1240TEST_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
1267TEST_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
1290TEST_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
1323TEST_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
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
1354 ASSERT_EQ(ENOENT, test_open(dir_s3d3, O_RDONLY));
1355}
1356
1357enum relative_access {
1358 REL_OPEN,
1359 REL_CHDIR,
1360 REL_CHROOT_ONLY,
1361 REL_CHROOT_CHDIR,
1362};
1363
1364static void test_relative_path(struct __test_metadata *const _metadata,
1365 const enum relative_access rel)
1366{
1367
1368
1369
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
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
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
1448 ASSERT_EQ(0, test_open_rel(dirfd, "./s2d3", O_RDONLY));
1449 } else {
1450
1451 ASSERT_EQ(0, test_open_rel(dirfd, "./s1d3", O_RDONLY));
1452 }
1453
1454 if (rel == REL_CHROOT_ONLY || rel == REL_CHROOT_CHDIR) {
1455
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
1477TEST_F_FORK(layout1, relative_open)
1478{
1479 test_relative_path(_metadata, REL_OPEN);
1480}
1481
1482TEST_F_FORK(layout1, relative_chdir)
1483{
1484 test_relative_path(_metadata, REL_CHDIR);
1485}
1486
1487TEST_F_FORK(layout1, relative_chroot_only)
1488{
1489 test_relative_path(_metadata, REL_CHROOT_ONLY);
1490}
1491
1492TEST_F_FORK(layout1, relative_chroot_chdir)
1493{
1494 test_relative_path(_metadata, REL_CHROOT_CHDIR);
1495}
1496
1497static 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
1520static 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
1545TEST_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
1578TEST_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
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
1611TEST_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
1637
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
1650
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
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
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
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
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
1688TEST_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
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
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
1725
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
1736
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
1746TEST_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
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
1783TEST_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
1807static 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
1858TEST_F_FORK(layout1, make_char)
1859{
1860
1861 set_cap(_metadata, CAP_MKNOD);
1862 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_CHAR, S_IFCHR,
1863 makedev(1, 3));
1864}
1865
1866TEST_F_FORK(layout1, make_block)
1867{
1868
1869 set_cap(_metadata, CAP_MKNOD);
1870 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_BLOCK, S_IFBLK,
1871 makedev(7, 0));
1872}
1873
1874TEST_F_FORK(layout1, make_reg_1)
1875{
1876 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFREG, 0);
1877}
1878
1879TEST_F_FORK(layout1, make_reg_2)
1880{
1881 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 0, 0);
1882}
1883
1884TEST_F_FORK(layout1, make_sock)
1885{
1886 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_SOCK, S_IFSOCK, 0);
1887}
1888
1889TEST_F_FORK(layout1, make_fifo)
1890{
1891 test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_FIFO, S_IFIFO, 0);
1892}
1893
1894TEST_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
1939TEST_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
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
1967static 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
1979TEST_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
2017TEST_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
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
2039 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR));
2040 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDWR));
2041
2042
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
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
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
2073FIXTURE(layout1_bind) {
2074};
2075
2076FIXTURE_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
2087FIXTURE_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
2098static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3";
2099static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1";
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127TEST_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
2149TEST_F_FORK(layout1_bind, same_content_same_file)
2150{
2151
2152
2153
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
2168
2169
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
2183 const struct rule layer3_source[] = {
2184 {
2185 .path = dir_s1d3,
2186 .access = LANDLOCK_ACCESS_FS_READ_FILE,
2187 },
2188 {}
2189 };
2190
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
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
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
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
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
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
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
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
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
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
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
2277 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY));
2278 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_WRONLY));
2279
2280
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"
2287static const char lower_fl1[] = LOWER_DATA "/fl1";
2288static const char lower_dl1[] = LOWER_DATA "/dl1";
2289static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2";
2290static const char lower_fo1[] = LOWER_DATA "/fo1";
2291static const char lower_do1[] = LOWER_DATA "/do1";
2292static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2";
2293static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3";
2294
2295static const char (*lower_base_files[])[] = {
2296 &lower_fl1,
2297 &lower_fo1,
2298 NULL
2299};
2300static const char (*lower_base_directories[])[] = {
2301 &lower_dl1,
2302 &lower_do1,
2303 NULL
2304};
2305static 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"
2315static const char upper_fu1[] = UPPER_DATA "/fu1";
2316static const char upper_du1[] = UPPER_DATA "/du1";
2317static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2";
2318static const char upper_fo1[] = UPPER_DATA "/fo1";
2319static const char upper_do1[] = UPPER_DATA "/do1";
2320static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2";
2321static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3";
2322
2323static const char (*upper_base_files[])[] = {
2324 &upper_fu1,
2325 &upper_fo1,
2326 NULL
2327};
2328static const char (*upper_base_directories[])[] = {
2329 &upper_du1,
2330 &upper_do1,
2331 NULL
2332};
2333static 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"
2342static const char merge_fl1[] = MERGE_DATA "/fl1";
2343static const char merge_dl1[] = MERGE_DATA "/dl1";
2344static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2";
2345static const char merge_fu1[] = MERGE_DATA "/fu1";
2346static const char merge_du1[] = MERGE_DATA "/du1";
2347static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2";
2348static const char merge_fo1[] = MERGE_DATA "/fo1";
2349static const char merge_do1[] = MERGE_DATA "/do1";
2350static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2";
2351static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3";
2352static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3";
2353
2354static const char (*merge_base_files[])[] = {
2355 &merge_fl1,
2356 &merge_fu1,
2357 &merge_fo1,
2358 NULL
2359};
2360static const char (*merge_base_directories[])[] = {
2361 &merge_dl1,
2362 &merge_du1,
2363 &merge_do1,
2364 NULL
2365};
2366static 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
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414FIXTURE(layout2_overlay) {
2415};
2416
2417FIXTURE_SETUP(layout2_overlay)
2418{
2419 prepare_layout(_metadata);
2420
2421 create_directory(_metadata, LOWER_BASE);
2422 set_cap(_metadata, CAP_SYS_ADMIN);
2423
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
2454FIXTURE_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
2485TEST_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
2520TEST_F_FORK(layout2_overlay, same_content_different_file)
2521{
2522
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
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
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
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
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
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
2682
2683
2684
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
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
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
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
2720 for_each_path(lower_base_files, path_entry, i) {
2721 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2722 }
2723
2724 for_each_path(upper_base_files, path_entry, i) {
2725 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2726 }
2727
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
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
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
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
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
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
2772 for_each_path(lower_sub_files, path_entry, i) {
2773 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2774 }
2775
2776 for_each_path(upper_sub_files, path_entry, i) {
2777 ASSERT_EQ(EACCES, test_open(path_entry, O_RDONLY));
2778 }
2779
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
2791TEST_HARNESS_MAIN
2792