Signed-off-by: Chris Down --- .../mseal_system_mappings/sysmap_is_sealed.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c b/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c index ea75ad537620..83b4fadfbfe7 100644 --- a/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +++ b/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -232,4 +233,95 @@ TEST_F(basic, check_sealed) EXPECT_EQ(expected, sealed); }; +static bool find_vdso(unsigned long *start, unsigned long *end) +{ + char line[MAX_LINE_LEN]; + bool found = false; + FILE *maps; + + maps = fopen("/proc/self/maps", "r"); + if (!maps) + return false; + + while (fgets(line, sizeof(line), maps)) { + if (strstr(line, "[vdso]") && + sscanf(line, "%lx-%lx", start, end) == 2) { + found = true; + break; + } + } + + fclose(maps); + return found; +} + +static int vdso_is_sealed(void) +{ + int sealed = -1; + FILE *maps; + + maps = fopen("/proc/self/smaps", "r"); + if (!maps) + return -1; + if (has_mapping("[vdso]", maps)) + sealed = mapping_is_sealed(maps); + fclose(maps); + return sealed; +} + +/* + * Unmapping or moving [vdso] must fail with EPERM when it is sealed. When it + * is not sealed, it succeeds and leaves glibc with a stale vdso pointer, which + * is fine because each test runs in its own forked child. + */ +TEST(vdso_munmap) +{ + int sealed; + unsigned long start, end; + int ret; + + if (!find_vdso(&start, &end)) + SKIP(return, "could not find the mapping, [vdso]"); + sealed = vdso_is_sealed(); + if (sealed < 0) + SKIP(return, "could not read the [vdso] sealing state"); + + ret = munmap((void *)start, end - start); + if (sealed) { + EXPECT_EQ(-1, ret); + EXPECT_EQ(EPERM, errno); + } else { + EXPECT_EQ(0, ret); + } + EXPECT_EQ(sealed, find_vdso(&start, &end)); +} + +TEST(vdso_mremap) +{ + int sealed; + unsigned long start, end, size, new_start; + void *dst, *ret; + + if (!find_vdso(&start, &end)) + SKIP(return, "could not find the mapping, [vdso]"); + sealed = vdso_is_sealed(); + if (sealed < 0) + SKIP(return, "could not read the [vdso] sealing state"); + size = end - start; + + dst = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, dst); + + ret = mremap((void *)start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, + dst); + if (sealed) { + EXPECT_EQ(MAP_FAILED, ret); + EXPECT_EQ(EPERM, errno); + } else { + EXPECT_EQ(dst, ret); + } + ASSERT_TRUE(find_vdso(&new_start, &end)); + EXPECT_EQ(sealed ? start : (unsigned long)dst, new_start); +} + TEST_HARNESS_MAIN -- 2.54.0