1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <sys/mman.h> 4 #include <stdint.h> 5 #include <asm-generic/unistd.h> 6 #include <string.h> 7 #include <sys/time.h> 8 #include <sys/resource.h> 9 #include <stdbool.h> 10 #include "../kselftest.h" 11 #include <syscall.h> 12 #include <errno.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <fcntl.h> 16 #include <sys/ioctl.h> 17 #include <sys/vfs.h> 18 #include <sys/stat.h> 19 #include "mseal_helpers.h" 20 21 /* 22 * define sys_xyx to call syscall directly. 23 */ 24 static int sys_mseal(void *start, size_t len) 25 { 26 int sret; 27 28 errno = 0; 29 sret = syscall(__NR_mseal, start, len, 0); 30 return sret; 31 } 32 33 static inline int sys_mprotect(void *ptr, size_t size, unsigned long prot) 34 { 35 int sret; 36 37 errno = 0; 38 sret = syscall(__NR_mprotect, ptr, size, prot); 39 return sret; 40 } 41 42 static bool seal_support(void) 43 { 44 int ret; 45 void *ptr; 46 unsigned long page_size = getpagesize(); 47 48 ptr = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 49 if (ptr == (void *) -1) 50 return false; 51 52 ret = sys_mseal(ptr, page_size); 53 if (ret < 0) 54 return false; 55 56 return true; 57 } 58 59 const char somestr[4096] = {"READONLY"}; 60 61 static void test_seal_elf(void) 62 { 63 int ret; 64 FILE *maps; 65 char line[512]; 66 uintptr_t addr_start, addr_end; 67 char prot[5]; 68 char filename[256]; 69 unsigned long page_size = getpagesize(); 70 unsigned long long ptr = (unsigned long long) somestr; 71 char *somestr2 = (char *)somestr; 72 73 /* 74 * Modify the protection of readonly somestr 75 */ 76 if (((unsigned long long)ptr % page_size) != 0) 77 ptr = (unsigned long long)ptr & ~(page_size - 1); 78 79 ksft_print_msg("somestr = %s\n", somestr); 80 ksft_print_msg("change protection to rw\n"); 81 ret = sys_mprotect((void *)ptr, page_size, PROT_READ|PROT_WRITE); 82 FAIL_TEST_IF_FALSE(!ret); 83 *somestr2 = 'A'; 84 ksft_print_msg("somestr is modified to: %s\n", somestr); 85 ret = sys_mprotect((void *)ptr, page_size, PROT_READ); 86 FAIL_TEST_IF_FALSE(!ret); 87 88 maps = fopen("/proc/self/maps", "r"); 89 FAIL_TEST_IF_FALSE(maps); 90 91 /* 92 * apply sealing to elf binary 93 */ 94 while (fgets(line, sizeof(line), maps)) { 95 if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*u %255[^\n]", 96 &addr_start, &addr_end, prot, filename) == 4) { 97 if (strlen(filename)) { 98 /* 99 * seal the mapping if read only. 100 */ 101 if (strstr(prot, "r-")) { 102 ret = sys_mseal((void *)addr_start, addr_end - addr_start); 103 FAIL_TEST_IF_FALSE(!ret); 104 ksft_print_msg("sealed: %lx-%lx %s %s\n", 105 addr_start, addr_end, prot, filename); 106 if ((uintptr_t) somestr >= addr_start && 107 (uintptr_t) somestr <= addr_end) 108 ksft_print_msg("mapping for somestr found\n"); 109 } 110 } 111 } 112 } 113 fclose(maps); 114 115 ret = sys_mprotect((void *)ptr, page_size, PROT_READ | PROT_WRITE); 116 FAIL_TEST_IF_FALSE(ret < 0); 117 ksft_print_msg("somestr is sealed, mprotect is rejected\n"); 118 119 REPORT_TEST_PASS(); 120 } 121 122 int main(int argc, char **argv) 123 { 124 bool test_seal = seal_support(); 125 126 ksft_print_header(); 127 ksft_print_msg("pid=%d\n", getpid()); 128 129 if (!test_seal) 130 ksft_exit_skip("sealing not supported, check CONFIG_64BIT\n"); 131 132 ksft_set_plan(1); 133 134 test_seal_elf(); 135 136 ksft_finished(); 137 } 138