1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2024 Ampere Computing LLC
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 #include <sys/wait.h>
17
18 #include "kselftest.h"
19 #include "mte_common_util.h"
20 #include "mte_def.h"
21
22 #define TAG_CHECK_ON 0
23 #define TAG_CHECK_OFF 1
24
default_huge_page_size(void)25 static unsigned long default_huge_page_size(void)
26 {
27 unsigned long hps = 0;
28 char *line = NULL;
29 size_t linelen = 0;
30 FILE *f = fopen("/proc/meminfo", "r");
31
32 if (!f)
33 return 0;
34 while (getline(&line, &linelen, f) > 0) {
35 if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
36 hps <<= 10;
37 break;
38 }
39 }
40
41 free(line);
42 fclose(f);
43 return hps;
44 }
45
is_hugetlb_allocated(void)46 static bool is_hugetlb_allocated(void)
47 {
48 unsigned long hps = 0;
49 char *line = NULL;
50 size_t linelen = 0;
51 FILE *f = fopen("/proc/meminfo", "r");
52
53 if (!f)
54 return false;
55 while (getline(&line, &linelen, f) > 0) {
56 if (sscanf(line, "Hugetlb: %lu kB", &hps) == 1) {
57 hps <<= 10;
58 break;
59 }
60 }
61
62 free(line);
63 fclose(f);
64
65 if (hps > 0)
66 return true;
67
68 return false;
69 }
70
write_sysfs(char * str,unsigned long val)71 static void write_sysfs(char *str, unsigned long val)
72 {
73 FILE *f;
74
75 f = fopen(str, "w");
76 if (!f) {
77 ksft_print_msg("ERR: missing %s\n", str);
78 return;
79 }
80 fprintf(f, "%lu", val);
81 fclose(f);
82 }
83
allocate_hugetlb()84 static void allocate_hugetlb()
85 {
86 write_sysfs("/proc/sys/vm/nr_hugepages", 2);
87 }
88
free_hugetlb()89 static void free_hugetlb()
90 {
91 write_sysfs("/proc/sys/vm/nr_hugepages", 0);
92 }
93
check_child_tag_inheritance(char * ptr,int size,int mode)94 static int check_child_tag_inheritance(char *ptr, int size, int mode)
95 {
96 int i, parent_tag, child_tag, fault, child_status;
97 pid_t child;
98
99 parent_tag = MT_FETCH_TAG((uintptr_t)ptr);
100 fault = 0;
101
102 child = fork();
103 if (child == -1) {
104 ksft_print_msg("FAIL: child process creation\n");
105 return KSFT_FAIL;
106 } else if (child == 0) {
107 mte_initialize_current_context(mode, (uintptr_t)ptr, size);
108 /* Do copy on write */
109 memset(ptr, '1', size);
110 mte_wait_after_trig();
111 if (cur_mte_cxt.fault_valid == true) {
112 fault = 1;
113 goto check_child_tag_inheritance_err;
114 }
115 for (i = 0; i < size; i += MT_GRANULE_SIZE) {
116 child_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
117 if (parent_tag != child_tag) {
118 ksft_print_msg("FAIL: child mte tag (%d) mismatch\n", i);
119 fault = 1;
120 goto check_child_tag_inheritance_err;
121 }
122 }
123 check_child_tag_inheritance_err:
124 _exit(fault);
125 }
126 /* Wait for child process to terminate */
127 wait(&child_status);
128 if (WIFEXITED(child_status))
129 fault = WEXITSTATUS(child_status);
130 else
131 fault = 1;
132 return (fault) ? KSFT_FAIL : KSFT_PASS;
133 }
134
check_mte_memory(char * ptr,int size,int mode,int tag_check)135 static int check_mte_memory(char *ptr, int size, int mode, int tag_check)
136 {
137 mte_initialize_current_context(mode, (uintptr_t)ptr, size);
138 memset(ptr, '1', size);
139 mte_wait_after_trig();
140 if (cur_mte_cxt.fault_valid == true)
141 return KSFT_FAIL;
142
143 return KSFT_PASS;
144 }
145
check_hugetlb_memory_mapping(int mem_type,int mode,int mapping,int tag_check)146 static int check_hugetlb_memory_mapping(int mem_type, int mode, int mapping, int tag_check)
147 {
148 char *ptr, *map_ptr;
149 int result;
150 unsigned long map_size;
151
152 map_size = default_huge_page_size();
153
154 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
155 map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
156 if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS)
157 return KSFT_FAIL;
158
159 mte_initialize_current_context(mode, (uintptr_t)map_ptr, map_size);
160 /* Only mte enabled memory will allow tag insertion */
161 ptr = mte_insert_tags((void *)map_ptr, map_size);
162 if (!ptr || cur_mte_cxt.fault_valid == true) {
163 ksft_print_msg("FAIL: Insert tags on anonymous mmap memory\n");
164 munmap((void *)map_ptr, map_size);
165 return KSFT_FAIL;
166 }
167 result = check_mte_memory(ptr, map_size, mode, tag_check);
168 mte_clear_tags((void *)ptr, map_size);
169 mte_free_memory((void *)map_ptr, map_size, mem_type, false);
170 if (result == KSFT_FAIL)
171 return KSFT_FAIL;
172
173 return KSFT_PASS;
174 }
175
check_clear_prot_mte_flag(int mem_type,int mode,int mapping)176 static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
177 {
178 char *map_ptr;
179 int prot_flag, result;
180 unsigned long map_size;
181
182 prot_flag = PROT_READ | PROT_WRITE;
183 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
184 map_size = default_huge_page_size();
185 map_ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
186 0, 0);
187 if (check_allocated_memory_range(map_ptr, map_size, mem_type,
188 0, 0) != KSFT_PASS)
189 return KSFT_FAIL;
190 /* Try to clear PROT_MTE property and verify it by tag checking */
191 if (mprotect(map_ptr, map_size, prot_flag)) {
192 mte_free_memory_tag_range((void *)map_ptr, map_size, mem_type,
193 0, 0);
194 ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n");
195 return KSFT_FAIL;
196 }
197 result = check_mte_memory(map_ptr, map_size, mode, TAG_CHECK_ON);
198 mte_free_memory_tag_range((void *)map_ptr, map_size, mem_type, 0, 0);
199 if (result != KSFT_PASS)
200 return KSFT_FAIL;
201
202 return KSFT_PASS;
203 }
204
check_child_hugetlb_memory_mapping(int mem_type,int mode,int mapping)205 static int check_child_hugetlb_memory_mapping(int mem_type, int mode, int mapping)
206 {
207 char *ptr;
208 int result;
209 unsigned long map_size;
210
211 map_size = default_huge_page_size();
212
213 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
214 ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
215 0, 0);
216 if (check_allocated_memory_range(ptr, map_size, mem_type,
217 0, 0) != KSFT_PASS)
218 return KSFT_FAIL;
219 result = check_child_tag_inheritance(ptr, map_size, mode);
220 mte_free_memory_tag_range((void *)ptr, map_size, mem_type, 0, 0);
221 if (result == KSFT_FAIL)
222 return result;
223
224 return KSFT_PASS;
225 }
226
main(int argc,char * argv[])227 int main(int argc, char *argv[])
228 {
229 int err;
230
231 err = mte_default_setup();
232 if (err)
233 return err;
234
235 /* Register signal handlers */
236 mte_register_signal(SIGBUS, mte_default_handler);
237 mte_register_signal(SIGSEGV, mte_default_handler);
238
239 allocate_hugetlb();
240
241 if (!is_hugetlb_allocated()) {
242 ksft_print_msg("ERR: Unable allocate hugetlb pages\n");
243 return KSFT_FAIL;
244 }
245
246 /* Set test plan */
247 ksft_set_plan(12);
248
249 mte_enable_pstate_tco();
250
251 evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
252 "Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check off\n");
253
254 mte_disable_pstate_tco();
255 evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_OFF),
256 "Check hugetlb memory with private mapping, no error mode, mmap memory and tag check off\n");
257
258 evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
259 "Check hugetlb memory with private mapping, sync error mode, mmap memory and tag check on\n");
260 evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
261 "Check hugetlb memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
262 evaluate_test(check_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
263 "Check hugetlb memory with private mapping, async error mode, mmap memory and tag check on\n");
264 evaluate_test(check_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB, TAG_CHECK_ON),
265 "Check hugetlb memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
266
267 evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
268 "Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n");
269 evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
270 "Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n");
271
272 evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
273 "Check child hugetlb memory with private mapping, precise mode and mmap memory\n");
274 evaluate_test(check_child_hugetlb_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
275 "Check child hugetlb memory with private mapping, precise mode and mmap memory\n");
276 evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
277 "Check child hugetlb memory with private mapping, precise mode and mmap/mprotect memory\n");
278 evaluate_test(check_child_hugetlb_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE | MAP_HUGETLB),
279 "Check child hugetlb memory with private mapping, precise mode and mmap/mprotect memory\n");
280
281 mte_restore_setup();
282 free_hugetlb();
283 ksft_print_cnts();
284 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
285 }
286