Skip to content

Commit 53ec81d

Browse files
amitdanielkachhapwilldeacon
authored andcommitted
kselftest/arm64: Verify all different mmap MTE options
This testcase checks the different unsupported/supported options for mmap if used with PROT_MTE memory protection flag. These checks are, * Either pstate.tco enable or prctl PR_MTE_TCF_NONE option should not cause any tag mismatch faults. * Different combinations of anonymous/file memory mmap, mprotect, sync/async error mode and private/shared mappings should work. * mprotect should not be able to clear the PROT_MTE page property. Co-developed-by: Gabor Kertesz <gabor.kertesz@arm.com> Signed-off-by: Gabor Kertesz <gabor.kertesz@arm.com> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com> Tested-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20201002115630.24683-5-amit.kachhap@arm.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent dfe537c commit 53ec81d

2 files changed

Lines changed: 263 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
check_buffer_fill
22
check_tags_inclusion
33
check_child_memory
4+
check_mmap_options
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
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+
mte_enable_pstate_tco();
209+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
210+
"Check anonymous memory with private mapping, sync error mode, mmap memory and tag check off\n");
211+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
212+
"Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check off\n");
213+
214+
mte_disable_pstate_tco();
215+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
216+
"Check anonymous memory with private mapping, no error mode, mmap memory and tag check off\n");
217+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
218+
"Check file memory with private mapping, no error mode, mmap/mprotect memory and tag check off\n");
219+
220+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
221+
"Check anonymous memory with private mapping, sync error mode, mmap memory and tag check on\n");
222+
evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
223+
"Check anonymous memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
224+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
225+
"Check anonymous memory with shared mapping, sync error mode, mmap memory and tag check on\n");
226+
evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
227+
"Check anonymous memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n");
228+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
229+
"Check anonymous memory with private mapping, async error mode, mmap memory and tag check on\n");
230+
evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
231+
"Check anonymous memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
232+
evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
233+
"Check anonymous memory with shared mapping, async error mode, mmap memory and tag check on\n");
234+
evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
235+
"Check anonymous memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n");
236+
237+
evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
238+
"Check file memory with private mapping, sync error mode, mmap memory and tag check on\n");
239+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
240+
"Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
241+
evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
242+
"Check file memory with shared mapping, sync error mode, mmap memory and tag check on\n");
243+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
244+
"Check file memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n");
245+
evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
246+
"Check file memory with private mapping, async error mode, mmap memory and tag check on\n");
247+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
248+
"Check file memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
249+
evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
250+
"Check file memory with shared mapping, async error mode, mmap memory and tag check on\n");
251+
evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
252+
"Check file memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n");
253+
254+
evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
255+
"Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n");
256+
evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
257+
"Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n");
258+
259+
mte_restore_setup();
260+
ksft_print_cnts();
261+
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
262+
}

0 commit comments

Comments
 (0)