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
27static size_t page_size;
28static 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
33static 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
60static 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
91static 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
130static 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
186int 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