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 <fcntl.h> 8 #include <signal.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <ucontext.h> 13 #include <sys/mman.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 17 #include "kselftest.h" 18 #include "mte_common_util.h" 19 #include "mte_def.h" 20 21 #define RUNS (MT_TAG_COUNT) 22 #define UNDERFLOW MT_GRANULE_SIZE 23 #define OVERFLOW MT_GRANULE_SIZE 24 #define TAG_CHECK_ON 0 25 #define TAG_CHECK_OFF 1 26 27 static size_t page_size; 28 static int sizes[] = { 29 1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE, 30 /* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0 31 }; 32 33 static int check_mte_memory(char *ptr, int size, int mode, int tag_check) 34 { 35 mte_initialize_current_context(mode, (uintptr_t)ptr, size); 36 memset(ptr, '1', size); 37 mte_wait_after_trig(); 38 if (cur_mte_cxt.fault_valid == true) 39 return KSFT_FAIL; 40 41 mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW); 42 memset(ptr - UNDERFLOW, '2', UNDERFLOW); 43 mte_wait_after_trig(); 44 if (cur_mte_cxt.fault_valid == false && tag_check == TAG_CHECK_ON) 45 return KSFT_FAIL; 46 if (cur_mte_cxt.fault_valid == true && tag_check == TAG_CHECK_OFF) 47 return KSFT_FAIL; 48 49 mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW); 50 memset(ptr + size, '3', OVERFLOW); 51 mte_wait_after_trig(); 52 if (cur_mte_cxt.fault_valid == false && tag_check == TAG_CHECK_ON) 53 return KSFT_FAIL; 54 if (cur_mte_cxt.fault_valid == true && tag_check == TAG_CHECK_OFF) 55 return KSFT_FAIL; 56 57 return KSFT_PASS; 58 } 59 60 static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, int tag_check) 61 { 62 char *ptr, *map_ptr; 63 int run, result, map_size; 64 int item = sizeof(sizes)/sizeof(int); 65 66 item = sizeof(sizes)/sizeof(int); 67 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); 68 for (run = 0; run < item; run++) { 69 map_size = sizes[run] + OVERFLOW + UNDERFLOW; 70 map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false); 71 if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) 72 return KSFT_FAIL; 73 74 ptr = map_ptr + UNDERFLOW; 75 mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]); 76 /* Only mte enabled memory will allow tag insertion */ 77 ptr = mte_insert_tags((void *)ptr, sizes[run]); 78 if (!ptr || cur_mte_cxt.fault_valid == true) { 79 ksft_print_msg("FAIL: Insert tags on anonymous mmap memory\n"); 80 munmap((void *)map_ptr, map_size); 81 return KSFT_FAIL; 82 } 83 result = check_mte_memory(ptr, sizes[run], mode, tag_check); 84 mte_clear_tags((void *)ptr, sizes[run]); 85 mte_free_memory((void *)map_ptr, map_size, mem_type, false); 86 if (result == KSFT_FAIL) 87 return KSFT_FAIL; 88 } 89 return KSFT_PASS; 90 } 91 92 static int check_file_memory_mapping(int mem_type, int mode, int mapping, int tag_check) 93 { 94 char *ptr, *map_ptr; 95 int run, fd, map_size; 96 int total = sizeof(sizes)/sizeof(int); 97 int result = KSFT_PASS; 98 99 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); 100 for (run = 0; run < total; run++) { 101 fd = create_temp_file(); 102 if (fd == -1) 103 return KSFT_FAIL; 104 105 map_size = sizes[run] + UNDERFLOW + OVERFLOW; 106 map_ptr = (char *)mte_allocate_file_memory(map_size, mem_type, mapping, false, fd); 107 if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) { 108 close(fd); 109 return KSFT_FAIL; 110 } 111 ptr = map_ptr + UNDERFLOW; 112 mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]); 113 /* Only mte enabled memory will allow tag insertion */ 114 ptr = mte_insert_tags((void *)ptr, sizes[run]); 115 if (!ptr || cur_mte_cxt.fault_valid == true) { 116 ksft_print_msg("FAIL: Insert tags on file based memory\n"); 117 munmap((void *)map_ptr, map_size); 118 close(fd); 119 return KSFT_FAIL; 120 } 121 result = check_mte_memory(ptr, sizes[run], mode, tag_check); 122 mte_clear_tags((void *)ptr, sizes[run]); 123 munmap((void *)map_ptr, map_size); 124 close(fd); 125 if (result == KSFT_FAIL) 126 break; 127 } 128 return result; 129 } 130 131 static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping) 132 { 133 char *ptr, *map_ptr; 134 int run, prot_flag, result, fd, map_size; 135 int total = sizeof(sizes)/sizeof(int); 136 137 prot_flag = PROT_READ | PROT_WRITE; 138 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); 139 for (run = 0; run < total; run++) { 140 map_size = sizes[run] + OVERFLOW + UNDERFLOW; 141 ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping, 142 UNDERFLOW, OVERFLOW); 143 if (check_allocated_memory_range(ptr, sizes[run], mem_type, 144 UNDERFLOW, OVERFLOW) != KSFT_PASS) 145 return KSFT_FAIL; 146 map_ptr = ptr - UNDERFLOW; 147 /* Try to clear PROT_MTE property and verify it by tag checking */ 148 if (mprotect(map_ptr, map_size, prot_flag)) { 149 mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, 150 UNDERFLOW, OVERFLOW); 151 ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n"); 152 return KSFT_FAIL; 153 } 154 result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON); 155 mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW); 156 if (result != KSFT_PASS) 157 return KSFT_FAIL; 158 159 fd = create_temp_file(); 160 if (fd == -1) 161 return KSFT_FAIL; 162 ptr = (char *)mte_allocate_file_memory_tag_range(sizes[run], mem_type, mapping, 163 UNDERFLOW, OVERFLOW, fd); 164 if (check_allocated_memory_range(ptr, sizes[run], mem_type, 165 UNDERFLOW, OVERFLOW) != KSFT_PASS) { 166 close(fd); 167 return KSFT_FAIL; 168 } 169 map_ptr = ptr - UNDERFLOW; 170 /* Try to clear PROT_MTE property and verify it by tag checking */ 171 if (mprotect(map_ptr, map_size, prot_flag)) { 172 ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n"); 173 mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, 174 UNDERFLOW, OVERFLOW); 175 close(fd); 176 return KSFT_FAIL; 177 } 178 result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON); 179 mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW); 180 close(fd); 181 if (result != KSFT_PASS) 182 return KSFT_FAIL; 183 } 184 return KSFT_PASS; 185 } 186 187 int main(int argc, char *argv[]) 188 { 189 int err; 190 int item = sizeof(sizes)/sizeof(int); 191 192 err = mte_default_setup(); 193 if (err) 194 return err; 195 page_size = getpagesize(); 196 if (!page_size) { 197 ksft_print_msg("ERR: Unable to get page size\n"); 198 return KSFT_FAIL; 199 } 200 sizes[item - 3] = page_size - 1; 201 sizes[item - 2] = page_size; 202 sizes[item - 1] = page_size + 1; 203 204 /* Register signal handlers */ 205 mte_register_signal(SIGBUS, mte_default_handler); 206 mte_register_signal(SIGSEGV, mte_default_handler); 207 208 /* Set test plan */ 209 ksft_set_plan(22); 210 211 mte_enable_pstate_tco(); 212 213 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 214 "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check off\n"); 215 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 216 "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check off\n"); 217 218 mte_disable_pstate_tco(); 219 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 220 "Check anonymous memory with private mapping, no error mode, mmap memory and tag check off\n"); 221 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 222 "Check file memory with private mapping, no error mode, mmap/mprotect memory and tag check off\n"); 223 224 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 225 "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check on\n"); 226 evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 227 "Check anonymous memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 228 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 229 "Check anonymous memory with shared mapping, sync error mode, mmap memory and tag check on\n"); 230 evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 231 "Check anonymous memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 232 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 233 "Check anonymous memory with private mapping, async error mode, mmap memory and tag check on\n"); 234 evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 235 "Check anonymous memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n"); 236 evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 237 "Check anonymous memory with shared mapping, async error mode, mmap memory and tag check on\n"); 238 evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 239 "Check anonymous memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n"); 240 241 evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 242 "Check file memory with private mapping, sync error mode, mmap memory and tag check on\n"); 243 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 244 "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 245 evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 246 "Check file memory with shared mapping, sync error mode, mmap memory and tag check on\n"); 247 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 248 "Check file memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 249 evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 250 "Check file memory with private mapping, async error mode, mmap memory and tag check on\n"); 251 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 252 "Check file memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n"); 253 evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 254 "Check file memory with shared mapping, async error mode, mmap memory and tag check on\n"); 255 evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 256 "Check file memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n"); 257 258 evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE), 259 "Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n"); 260 evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE), 261 "Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n"); 262 263 mte_restore_setup(); 264 ksft_print_cnts(); 265 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 266 } 267