|
28 | 28 | #define MFD_DEF_SIZE 8192
|
29 | 29 | #define STACK_SIZE 65536
|
30 | 30 |
|
| 31 | +#define F_SEAL_EXEC 0x0020 |
| 32 | + |
31 | 33 | /*
|
32 | 34 | * Default is not to test hugetlbfs
|
33 | 35 | */
|
34 | 36 | static size_t mfd_def_size = MFD_DEF_SIZE;
|
35 | 37 | static const char *memfd_str = MEMFD_STR;
|
36 | 38 |
|
| 39 | +static ssize_t fd2name(int fd, char *buf, size_t bufsize) |
| 40 | +{ |
| 41 | + char buf1[PATH_MAX]; |
| 42 | + int size; |
| 43 | + ssize_t nbytes; |
| 44 | + |
| 45 | + size = snprintf(buf1, PATH_MAX, "/proc/self/fd/%d", fd); |
| 46 | + if (size < 0) { |
| 47 | + printf("snprintf(%d) failed on %m\n", fd); |
| 48 | + abort(); |
| 49 | + } |
| 50 | + |
| 51 | + /* |
| 52 | + * reserver one byte for string termination. |
| 53 | + */ |
| 54 | + nbytes = readlink(buf1, buf, bufsize-1); |
| 55 | + if (nbytes == -1) { |
| 56 | + printf("readlink(%s) failed %m\n", buf1); |
| 57 | + abort(); |
| 58 | + } |
| 59 | + buf[nbytes] = '\0'; |
| 60 | + return nbytes; |
| 61 | +} |
| 62 | + |
37 | 63 | static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
|
38 | 64 | {
|
39 | 65 | int r, fd;
|
@@ -98,11 +124,14 @@ static unsigned int mfd_assert_get_seals(int fd)
|
98 | 124 |
|
99 | 125 | static void mfd_assert_has_seals(int fd, unsigned int seals)
|
100 | 126 | {
|
| 127 | + char buf[PATH_MAX]; |
| 128 | + int nbytes; |
101 | 129 | unsigned int s;
|
| 130 | + fd2name(fd, buf, PATH_MAX); |
102 | 131 |
|
103 | 132 | s = mfd_assert_get_seals(fd);
|
104 | 133 | if (s != seals) {
|
105 |
| - printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd); |
| 134 | + printf("%u != %u = GET_SEALS(%s)\n", seals, s, buf); |
106 | 135 | abort();
|
107 | 136 | }
|
108 | 137 | }
|
@@ -594,6 +623,64 @@ static void mfd_fail_grow_write(int fd)
|
594 | 623 | }
|
595 | 624 | }
|
596 | 625 |
|
| 626 | +static void mfd_assert_mode(int fd, int mode) |
| 627 | +{ |
| 628 | + struct stat st; |
| 629 | + char buf[PATH_MAX]; |
| 630 | + int nbytes; |
| 631 | + |
| 632 | + fd2name(fd, buf, PATH_MAX); |
| 633 | + |
| 634 | + if (fstat(fd, &st) < 0) { |
| 635 | + printf("fstat(%s) failed: %m\n", buf); |
| 636 | + abort(); |
| 637 | + } |
| 638 | + |
| 639 | + if ((st.st_mode & 07777) != mode) { |
| 640 | + printf("fstat(%s) wrong file mode 0%04o, but expected 0%04o\n", |
| 641 | + buf, (int)st.st_mode & 07777, mode); |
| 642 | + abort(); |
| 643 | + } |
| 644 | +} |
| 645 | + |
| 646 | +static void mfd_assert_chmod(int fd, int mode) |
| 647 | +{ |
| 648 | + char buf[PATH_MAX]; |
| 649 | + int nbytes; |
| 650 | + |
| 651 | + fd2name(fd, buf, PATH_MAX); |
| 652 | + |
| 653 | + if (fchmod(fd, mode) < 0) { |
| 654 | + printf("fchmod(%s, 0%04o) failed: %m\n", buf, mode); |
| 655 | + abort(); |
| 656 | + } |
| 657 | + |
| 658 | + mfd_assert_mode(fd, mode); |
| 659 | +} |
| 660 | + |
| 661 | +static void mfd_fail_chmod(int fd, int mode) |
| 662 | +{ |
| 663 | + struct stat st; |
| 664 | + char buf[PATH_MAX]; |
| 665 | + int nbytes; |
| 666 | + |
| 667 | + fd2name(fd, buf, PATH_MAX); |
| 668 | + |
| 669 | + if (fstat(fd, &st) < 0) { |
| 670 | + printf("fstat(%s) failed: %m\n", buf); |
| 671 | + abort(); |
| 672 | + } |
| 673 | + |
| 674 | + if (fchmod(fd, mode) == 0) { |
| 675 | + printf("fchmod(%s, 0%04o) didn't fail as expected\n", |
| 676 | + buf, mode); |
| 677 | + abort(); |
| 678 | + } |
| 679 | + |
| 680 | + /* verify that file mode bits did not change */ |
| 681 | + mfd_assert_mode(fd, st.st_mode & 07777); |
| 682 | +} |
| 683 | + |
597 | 684 | static int idle_thread_fn(void *arg)
|
598 | 685 | {
|
599 | 686 | sigset_t set;
|
@@ -880,6 +967,39 @@ static void test_seal_resize(void)
|
880 | 967 | close(fd);
|
881 | 968 | }
|
882 | 969 |
|
| 970 | +/* |
| 971 | + * Test SEAL_EXEC |
| 972 | + * Test that chmod() cannot change x bits after sealing |
| 973 | + */ |
| 974 | +static void test_seal_exec(void) |
| 975 | +{ |
| 976 | + int fd; |
| 977 | + |
| 978 | + printf("%s SEAL-EXEC\n", memfd_str); |
| 979 | + |
| 980 | + fd = mfd_assert_new("kern_memfd_seal_exec", |
| 981 | + mfd_def_size, |
| 982 | + MFD_CLOEXEC | MFD_ALLOW_SEALING); |
| 983 | + |
| 984 | + mfd_assert_mode(fd, 0777); |
| 985 | + |
| 986 | + mfd_assert_chmod(fd, 0644); |
| 987 | + |
| 988 | + mfd_assert_has_seals(fd, 0); |
| 989 | + mfd_assert_add_seals(fd, F_SEAL_EXEC); |
| 990 | + mfd_assert_has_seals(fd, F_SEAL_EXEC); |
| 991 | + |
| 992 | + mfd_assert_chmod(fd, 0600); |
| 993 | + mfd_fail_chmod(fd, 0777); |
| 994 | + mfd_fail_chmod(fd, 0670); |
| 995 | + mfd_fail_chmod(fd, 0605); |
| 996 | + mfd_fail_chmod(fd, 0700); |
| 997 | + mfd_fail_chmod(fd, 0100); |
| 998 | + mfd_assert_chmod(fd, 0666); |
| 999 | + |
| 1000 | + close(fd); |
| 1001 | +} |
| 1002 | + |
883 | 1003 | /*
|
884 | 1004 | * Test sharing via dup()
|
885 | 1005 | * Test that seals are shared between dupped FDs and they're all equal.
|
@@ -1059,6 +1179,7 @@ int main(int argc, char **argv)
|
1059 | 1179 | test_seal_shrink();
|
1060 | 1180 | test_seal_grow();
|
1061 | 1181 | test_seal_resize();
|
| 1182 | + test_seal_exec(); |
1062 | 1183 |
|
1063 | 1184 | test_share_dup("SHARE-DUP", "");
|
1064 | 1185 | test_share_mmap("SHARE-MMAP", "");
|
|
0 commit comments