Skip to content

Commit 32d118a

Browse files
danielverkampakpm00
authored andcommitted
selftests/memfd: add tests for F_SEAL_EXEC
Basic tests to ensure that user/group/other execute bits cannot be changed after applying F_SEAL_EXEC to a memfd. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Daniel Verkamp <[email protected]> Co-developed-by: Jeff Xu <[email protected]> Signed-off-by: Jeff Xu <[email protected]> Reviewed-by: Kees Cook <[email protected]> Cc: David Herrmann <[email protected]> Cc: Dmitry Torokhov <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Jann Horn <[email protected]> Cc: Jorge Lucangeli Obes <[email protected]> Cc: kernel test robot <[email protected]> Cc: Shuah Khan <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 6fd7353 commit 32d118a

File tree

1 file changed

+122
-1
lines changed

1 file changed

+122
-1
lines changed

tools/testing/selftests/memfd/memfd_test.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,38 @@
2828
#define MFD_DEF_SIZE 8192
2929
#define STACK_SIZE 65536
3030

31+
#define F_SEAL_EXEC 0x0020
32+
3133
/*
3234
* Default is not to test hugetlbfs
3335
*/
3436
static size_t mfd_def_size = MFD_DEF_SIZE;
3537
static const char *memfd_str = MEMFD_STR;
3638

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+
3763
static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
3864
{
3965
int r, fd;
@@ -98,11 +124,14 @@ static unsigned int mfd_assert_get_seals(int fd)
98124

99125
static void mfd_assert_has_seals(int fd, unsigned int seals)
100126
{
127+
char buf[PATH_MAX];
128+
int nbytes;
101129
unsigned int s;
130+
fd2name(fd, buf, PATH_MAX);
102131

103132
s = mfd_assert_get_seals(fd);
104133
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);
106135
abort();
107136
}
108137
}
@@ -594,6 +623,64 @@ static void mfd_fail_grow_write(int fd)
594623
}
595624
}
596625

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+
597684
static int idle_thread_fn(void *arg)
598685
{
599686
sigset_t set;
@@ -880,6 +967,39 @@ static void test_seal_resize(void)
880967
close(fd);
881968
}
882969

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+
8831003
/*
8841004
* Test sharing via dup()
8851005
* Test that seals are shared between dupped FDs and they're all equal.
@@ -1059,6 +1179,7 @@ int main(int argc, char **argv)
10591179
test_seal_shrink();
10601180
test_seal_grow();
10611181
test_seal_resize();
1182+
test_seal_exec();
10621183

10631184
test_share_dup("SHARE-DUP", "");
10641185
test_share_mmap("SHARE-MMAP", "");

0 commit comments

Comments
 (0)