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
check_mte_memory(char * ptr,int size,int mode,int tag_check)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
check_anonymous_memory_mapping(int mem_type,int mode,int mapping,int tag_check)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
check_file_memory_mapping(int mem_type,int mode,int mapping,int tag_check)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
check_clear_prot_mte_flag(int mem_type,int mode,int mapping)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
main(int argc,char * argv[])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