Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kselftest/arm64: Verify all different mmap MTE options

This testcase checks the different unsupported/supported options for mmap
if used with PROT_MTE memory protection flag. These checks are,

* Either pstate.tco enable or prctl PR_MTE_TCF_NONE option should not cause
any tag mismatch faults.
* Different combinations of anonymous/file memory mmap, mprotect,
sync/async error mode and private/shared mappings should work.
* mprotect should not be able to clear the PROT_MTE page property.

Co-developed-by: Gabor Kertesz <gabor.kertesz@arm.com>
Signed-off-by: Gabor Kertesz <gabor.kertesz@arm.com>
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com>
Tested-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20201002115630.24683-5-amit.kachhap@arm.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Amit Daniel Kachhap and committed by
Will Deacon
53ec81d2 dfe537cf

+263
+1
tools/testing/selftests/arm64/mte/.gitignore
··· 1 1 check_buffer_fill 2 2 check_tags_inclusion 3 3 check_child_memory 4 + check_mmap_options
+262
tools/testing/selftests/arm64/mte/check_mmap_options.c
··· 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 + mte_enable_pstate_tco(); 209 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 210 + "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check off\n"); 211 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 212 + "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check off\n"); 213 + 214 + mte_disable_pstate_tco(); 215 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 216 + "Check anonymous memory with private mapping, no error mode, mmap memory and tag check off\n"); 217 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF), 218 + "Check file memory with private mapping, no error mode, mmap/mprotect memory and tag check off\n"); 219 + 220 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 221 + "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check on\n"); 222 + evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 223 + "Check anonymous memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 224 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 225 + "Check anonymous memory with shared mapping, sync error mode, mmap memory and tag check on\n"); 226 + evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 227 + "Check anonymous memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 228 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 229 + "Check anonymous memory with private mapping, async error mode, mmap memory and tag check on\n"); 230 + evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 231 + "Check anonymous memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n"); 232 + evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 233 + "Check anonymous memory with shared mapping, async error mode, mmap memory and tag check on\n"); 234 + evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 235 + "Check anonymous memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n"); 236 + 237 + evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 238 + "Check file memory with private mapping, sync error mode, mmap memory and tag check on\n"); 239 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 240 + "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 241 + evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 242 + "Check file memory with shared mapping, sync error mode, mmap memory and tag check on\n"); 243 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 244 + "Check file memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n"); 245 + evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 246 + "Check file memory with private mapping, async error mode, mmap memory and tag check on\n"); 247 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON), 248 + "Check file memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n"); 249 + evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 250 + "Check file memory with shared mapping, async error mode, mmap memory and tag check on\n"); 251 + evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON), 252 + "Check file memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n"); 253 + 254 + evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE), 255 + "Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n"); 256 + evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE), 257 + "Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n"); 258 + 259 + mte_restore_setup(); 260 + ksft_print_cnts(); 261 + return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; 262 + }