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