// SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE #include #include #include #include #include #include #include #include "../kselftest.h" #include #include #include #include #include #include #include #include #include "mseal_helpers.h" /* * define sys_xyx to call syscall directly. */ static int sys_mseal(void *start, size_t len) { int sret; errno = 0; sret = syscall(__NR_mseal, start, len, 0); return sret; } static inline int sys_mprotect(void *ptr, size_t size, unsigned long prot) { int sret; errno = 0; sret = syscall(__NR_mprotect, ptr, size, prot); return sret; } static bool seal_support(void) { int ret; void *ptr; unsigned long page_size = getpagesize(); ptr = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (ptr == (void *) -1) return false; ret = sys_mseal(ptr, page_size); if (ret < 0) return false; return true; } const char somestr[4096] = {"READONLY"}; static void test_seal_elf(void) { int ret; FILE *maps; char line[512]; uintptr_t addr_start, addr_end; char prot[5]; char filename[256]; unsigned long page_size = getpagesize(); unsigned long long ptr = (unsigned long long) somestr; char *somestr2 = (char *)somestr; /* * Modify the protection of readonly somestr */ if (((unsigned long long)ptr % page_size) != 0) ptr = (unsigned long long)ptr & ~(page_size - 1); ksft_print_msg("somestr = %s\n", somestr); ksft_print_msg("change protection to rw\n"); ret = sys_mprotect((void *)ptr, page_size, PROT_READ|PROT_WRITE); FAIL_TEST_IF_FALSE(!ret); *somestr2 = 'A'; ksft_print_msg("somestr is modified to: %s\n", somestr); ret = sys_mprotect((void *)ptr, page_size, PROT_READ); FAIL_TEST_IF_FALSE(!ret); maps = fopen("/proc/self/maps", "r"); FAIL_TEST_IF_FALSE(maps); /* * apply sealing to elf binary */ while (fgets(line, sizeof(line), maps)) { if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*u %255[^\n]", &addr_start, &addr_end, prot, filename) == 4) { if (strlen(filename)) { /* * seal the mapping if read only. */ if (strstr(prot, "r-")) { ret = sys_mseal((void *)addr_start, addr_end - addr_start); FAIL_TEST_IF_FALSE(!ret); ksft_print_msg("sealed: %lx-%lx %s %s\n", addr_start, addr_end, prot, filename); if ((uintptr_t) somestr >= addr_start && (uintptr_t) somestr <= addr_end) ksft_print_msg("mapping for somestr found\n"); } } } } fclose(maps); ret = sys_mprotect((void *)ptr, page_size, PROT_READ | PROT_WRITE); FAIL_TEST_IF_FALSE(ret < 0); ksft_print_msg("somestr is sealed, mprotect is rejected\n"); REPORT_TEST_PASS(); } int main(int argc, char **argv) { bool test_seal = seal_support(); ksft_print_header(); ksft_print_msg("pid=%d\n", getpid()); if (!test_seal) ksft_exit_skip("sealing not supported, check CONFIG_64BIT\n"); ksft_set_plan(1); test_seal_elf(); ksft_finished(); }