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 	/* 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