1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2020 ARM Limited 3 4 #define _GNU_SOURCE 5 6 #include <errno.h> 7 #include <signal.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <ucontext.h> 12 #include <sys/wait.h> 13 14 #include "kselftest.h" 15 #include "mte_common_util.h" 16 #include "mte_def.h" 17 18 #define BUFFER_SIZE (5 * MT_GRANULE_SIZE) 19 #define RUNS (MT_TAG_COUNT) 20 #define UNDERFLOW MT_GRANULE_SIZE 21 #define OVERFLOW MT_GRANULE_SIZE 22 23 static size_t page_size; 24 static int sizes[] = { 25 1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE, 26 /* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0 27 }; 28 29 static int check_child_tag_inheritance(char *ptr, int size, int mode) 30 { 31 int i, parent_tag, child_tag, fault, child_status; 32 pid_t child; 33 34 parent_tag = MT_FETCH_TAG((uintptr_t)ptr); 35 fault = 0; 36 37 child = fork(); 38 if (child == -1) { 39 ksft_print_msg("FAIL: child process creation\n"); 40 return KSFT_FAIL; 41 } else if (child == 0) { 42 mte_initialize_current_context(mode, (uintptr_t)ptr, size); 43 /* Do copy on write */ 44 memset(ptr, '1', size); 45 mte_wait_after_trig(); 46 if (cur_mte_cxt.fault_valid == true) { 47 fault = 1; 48 goto check_child_tag_inheritance_err; 49 } 50 for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) { 51 child_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i))); 52 if (parent_tag != child_tag) { 53 ksft_print_msg("FAIL: child mte tag mismatch\n"); 54 fault = 1; 55 goto check_child_tag_inheritance_err; 56 } 57 } 58 mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW); 59 memset(ptr - UNDERFLOW, '2', UNDERFLOW); 60 mte_wait_after_trig(); 61 if (cur_mte_cxt.fault_valid == false) { 62 fault = 1; 63 goto check_child_tag_inheritance_err; 64 } 65 mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW); 66 memset(ptr + size, '3', OVERFLOW); 67 mte_wait_after_trig(); 68 if (cur_mte_cxt.fault_valid == false) { 69 fault = 1; 70 goto check_child_tag_inheritance_err; 71 } 72 check_child_tag_inheritance_err: 73 _exit(fault); 74 } 75 /* Wait for child process to terminate */ 76 wait(&child_status); 77 if (WIFEXITED(child_status)) 78 fault = WEXITSTATUS(child_status); 79 else 80 fault = 1; 81 return (fault) ? KSFT_FAIL : KSFT_PASS; 82 } 83 84 static int check_child_memory_mapping(int mem_type, int mode, int mapping) 85 { 86 char *ptr; 87 int run, result; 88 int item = sizeof(sizes)/sizeof(int); 89 90 item = sizeof(sizes)/sizeof(int); 91 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); 92 for (run = 0; run < item; run++) { 93 ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping, 94 UNDERFLOW, OVERFLOW); 95 if (check_allocated_memory_range(ptr, sizes[run], mem_type, 96 UNDERFLOW, OVERFLOW) != KSFT_PASS) 97 return KSFT_FAIL; 98 result = check_child_tag_inheritance(ptr, sizes[run], mode); 99 mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW); 100 if (result == KSFT_FAIL) 101 return result; 102 } 103 return KSFT_PASS; 104 } 105 106 static int check_child_file_mapping(int mem_type, int mode, int mapping) 107 { 108 char *ptr, *map_ptr; 109 int run, fd, map_size, result = KSFT_PASS; 110 int total = sizeof(sizes)/sizeof(int); 111 112 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); 113 for (run = 0; run < total; run++) { 114 fd = create_temp_file(); 115 if (fd == -1) 116 return KSFT_FAIL; 117 118 map_size = sizes[run] + OVERFLOW + UNDERFLOW; 119 map_ptr = (char *)mte_allocate_file_memory(map_size, mem_type, mapping, false, fd); 120 if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) { 121 close(fd); 122 return KSFT_FAIL; 123 } 124 ptr = map_ptr + UNDERFLOW; 125 mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]); 126 /* Only mte enabled memory will allow tag insertion */ 127 ptr = mte_insert_tags((void *)ptr, sizes[run]); 128 if (!ptr || cur_mte_cxt.fault_valid == true) { 129 ksft_print_msg("FAIL: Insert tags on file based memory\n"); 130 munmap((void *)map_ptr, map_size); 131 close(fd); 132 return KSFT_FAIL; 133 } 134 result = check_child_tag_inheritance(ptr, sizes[run], mode); 135 mte_clear_tags((void *)ptr, sizes[run]); 136 munmap((void *)map_ptr, map_size); 137 close(fd); 138 if (result != KSFT_PASS) 139 return KSFT_FAIL; 140 } 141 return KSFT_PASS; 142 } 143 144 int main(int argc, char *argv[]) 145 { 146 int err; 147 int item = sizeof(sizes)/sizeof(int); 148 149 page_size = getpagesize(); 150 if (!page_size) { 151 ksft_print_msg("ERR: Unable to get page size\n"); 152 return KSFT_FAIL; 153 } 154 sizes[item - 3] = page_size - 1; 155 sizes[item - 2] = page_size; 156 sizes[item - 1] = page_size + 1; 157 158 err = mte_default_setup(); 159 if (err) 160 return err; 161 162 /* Register SIGSEGV handler */ 163 mte_register_signal(SIGSEGV, mte_default_handler); 164 mte_register_signal(SIGBUS, mte_default_handler); 165 166 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE), 167 "Check child anonymous memory with private mapping, precise mode and mmap memory\n"); 168 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED), 169 "Check child anonymous memory with shared mapping, precise mode and mmap memory\n"); 170 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE), 171 "Check child anonymous memory with private mapping, imprecise mode and mmap memory\n"); 172 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED), 173 "Check child anonymous memory with shared mapping, imprecise mode and mmap memory\n"); 174 evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE), 175 "Check child anonymous memory with private mapping, precise mode and mmap/mprotect memory\n"); 176 evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED), 177 "Check child anonymous memory with shared mapping, precise mode and mmap/mprotect memory\n"); 178 179 evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE), 180 "Check child file memory with private mapping, precise mode and mmap memory\n"); 181 evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED), 182 "Check child file memory with shared mapping, precise mode and mmap memory\n"); 183 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE), 184 "Check child file memory with private mapping, imprecise mode and mmap memory\n"); 185 evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED), 186 "Check child file memory with shared mapping, imprecise mode and mmap memory\n"); 187 evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE), 188 "Check child file memory with private mapping, precise mode and mmap/mprotect memory\n"); 189 evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED), 190 "Check child file memory with shared mapping, precise mode and mmap/mprotect memory\n"); 191 192 mte_restore_setup(); 193 ksft_print_cnts(); 194 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 195 } 196