xref: /linux/tools/testing/selftests/arm64/mte/check_child_memory.c (revision be239684b18e1cdcafcf8c7face4a2f562c745ad)
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 <signal.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ucontext.h>
12 #include <sys/wait.h>
13 
14 #include "kselftest.h"
15 #include "mte_common_util.h"
16 #include "mte_def.h"
17 
18 #define BUFFER_SIZE		(5 * MT_GRANULE_SIZE)
19 #define RUNS			(MT_TAG_COUNT)
20 #define UNDERFLOW		MT_GRANULE_SIZE
21 #define OVERFLOW		MT_GRANULE_SIZE
22 
23 static size_t page_size;
24 static int sizes[] = {
25 	1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
26 	/* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
27 };
28 
29 static int check_child_tag_inheritance(char *ptr, int size, int mode)
30 {
31 	int i, parent_tag, child_tag, fault, child_status;
32 	pid_t child;
33 
34 	parent_tag = MT_FETCH_TAG((uintptr_t)ptr);
35 	fault = 0;
36 
37 	child = fork();
38 	if (child == -1) {
39 		ksft_print_msg("FAIL: child process creation\n");
40 		return KSFT_FAIL;
41 	} else if (child == 0) {
42 		mte_initialize_current_context(mode, (uintptr_t)ptr, size);
43 		/* Do copy on write */
44 		memset(ptr, '1', size);
45 		mte_wait_after_trig();
46 		if (cur_mte_cxt.fault_valid == true) {
47 			fault = 1;
48 			goto check_child_tag_inheritance_err;
49 		}
50 		for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) {
51 			child_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
52 			if (parent_tag != child_tag) {
53 				ksft_print_msg("FAIL: child mte tag mismatch\n");
54 				fault = 1;
55 				goto check_child_tag_inheritance_err;
56 			}
57 		}
58 		mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW);
59 		memset(ptr - UNDERFLOW, '2', UNDERFLOW);
60 		mte_wait_after_trig();
61 		if (cur_mte_cxt.fault_valid == false) {
62 			fault = 1;
63 			goto check_child_tag_inheritance_err;
64 		}
65 		mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW);
66 		memset(ptr + size, '3', OVERFLOW);
67 		mte_wait_after_trig();
68 		if (cur_mte_cxt.fault_valid == false) {
69 			fault = 1;
70 			goto check_child_tag_inheritance_err;
71 		}
72 check_child_tag_inheritance_err:
73 		_exit(fault);
74 	}
75 	/* Wait for child process to terminate */
76 	wait(&child_status);
77 	if (WIFEXITED(child_status))
78 		fault = WEXITSTATUS(child_status);
79 	else
80 		fault = 1;
81 	return (fault) ? KSFT_FAIL : KSFT_PASS;
82 }
83 
84 static int check_child_memory_mapping(int mem_type, int mode, int mapping)
85 {
86 	char *ptr;
87 	int run, result;
88 	int item = ARRAY_SIZE(sizes);
89 
90 	item = ARRAY_SIZE(sizes);
91 	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
92 	for (run = 0; run < item; run++) {
93 		ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping,
94 							    UNDERFLOW, OVERFLOW);
95 		if (check_allocated_memory_range(ptr, sizes[run], mem_type,
96 						 UNDERFLOW, OVERFLOW) != KSFT_PASS)
97 			return KSFT_FAIL;
98 		result = check_child_tag_inheritance(ptr, sizes[run], mode);
99 		mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
100 		if (result == KSFT_FAIL)
101 			return result;
102 	}
103 	return KSFT_PASS;
104 }
105 
106 static int check_child_file_mapping(int mem_type, int mode, int mapping)
107 {
108 	char *ptr, *map_ptr;
109 	int run, fd, map_size, result = KSFT_PASS;
110 	int total = ARRAY_SIZE(sizes);
111 
112 	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
113 	for (run = 0; run < total; run++) {
114 		fd = create_temp_file();
115 		if (fd == -1)
116 			return KSFT_FAIL;
117 
118 		map_size = sizes[run] + OVERFLOW + UNDERFLOW;
119 		map_ptr = (char *)mte_allocate_file_memory(map_size, mem_type, mapping, false, fd);
120 		if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) {
121 			close(fd);
122 			return KSFT_FAIL;
123 		}
124 		ptr = map_ptr + UNDERFLOW;
125 		mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]);
126 		/* Only mte enabled memory will allow tag insertion */
127 		ptr = mte_insert_tags((void *)ptr, sizes[run]);
128 		if (!ptr || cur_mte_cxt.fault_valid == true) {
129 			ksft_print_msg("FAIL: Insert tags on file based memory\n");
130 			munmap((void *)map_ptr, map_size);
131 			close(fd);
132 			return KSFT_FAIL;
133 		}
134 		result = check_child_tag_inheritance(ptr, sizes[run], mode);
135 		mte_clear_tags((void *)ptr, sizes[run]);
136 		munmap((void *)map_ptr, map_size);
137 		close(fd);
138 		if (result != KSFT_PASS)
139 			return KSFT_FAIL;
140 	}
141 	return KSFT_PASS;
142 }
143 
144 int main(int argc, char *argv[])
145 {
146 	int err;
147 	int item = ARRAY_SIZE(sizes);
148 
149 	page_size = getpagesize();
150 	if (!page_size) {
151 		ksft_print_msg("ERR: Unable to get page size\n");
152 		return KSFT_FAIL;
153 	}
154 	sizes[item - 3] = page_size - 1;
155 	sizes[item - 2] = page_size;
156 	sizes[item - 1] = page_size + 1;
157 
158 	err = mte_default_setup();
159 	if (err)
160 		return err;
161 
162 	/* Register SIGSEGV handler */
163 	mte_register_signal(SIGSEGV, mte_default_handler);
164 	mte_register_signal(SIGBUS, mte_default_handler);
165 
166 	/* Set test plan */
167 	ksft_set_plan(12);
168 
169 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
170 		"Check child anonymous memory with private mapping, precise mode and mmap memory\n");
171 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
172 		"Check child anonymous memory with shared mapping, precise mode and mmap memory\n");
173 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
174 		"Check child anonymous memory with private mapping, imprecise mode and mmap memory\n");
175 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
176 		"Check child anonymous memory with shared mapping, imprecise mode and mmap memory\n");
177 	evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
178 		"Check child anonymous memory with private mapping, precise mode and mmap/mprotect memory\n");
179 	evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
180 		"Check child anonymous memory with shared mapping, precise mode and mmap/mprotect memory\n");
181 
182 	evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
183 		"Check child file memory with private mapping, precise mode and mmap memory\n");
184 	evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
185 		"Check child file memory with shared mapping, precise mode and mmap memory\n");
186 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
187 		"Check child file memory with private mapping, imprecise mode and mmap memory\n");
188 	evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
189 		"Check child file memory with shared mapping, imprecise mode and mmap memory\n");
190 	evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
191 		"Check child file memory with private mapping, precise mode and mmap/mprotect memory\n");
192 	evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
193 		"Check child file memory with shared mapping, precise mode and mmap/mprotect memory\n");
194 
195 	mte_restore_setup();
196 	ksft_print_cnts();
197 	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
198 }
199