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 = 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 
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 
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 
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