xref: /optee_os/core/kernel/asan.c (revision 1d171f95db3ea1187f5ff0ae98c49ce400fc8eb6)
1*1d171f95SJens Wiklander /*
2*1d171f95SJens Wiklander  * Copyright (c) 2016, Linaro Limited
3*1d171f95SJens Wiklander  * All rights reserved.
4*1d171f95SJens Wiklander  *
5*1d171f95SJens Wiklander  * Redistribution and use in source and binary forms, with or without
6*1d171f95SJens Wiklander  * modification, are permitted provided that the following conditions are met:
7*1d171f95SJens Wiklander  *
8*1d171f95SJens Wiklander  * 1. Redistributions of source code must retain the above copyright notice,
9*1d171f95SJens Wiklander  * this list of conditions and the following disclaimer.
10*1d171f95SJens Wiklander  *
11*1d171f95SJens Wiklander  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*1d171f95SJens Wiklander  * this list of conditions and the following disclaimer in the documentation
13*1d171f95SJens Wiklander  * and/or other materials provided with the distribution.
14*1d171f95SJens Wiklander  *
15*1d171f95SJens Wiklander  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16*1d171f95SJens Wiklander  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*1d171f95SJens Wiklander  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*1d171f95SJens Wiklander  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19*1d171f95SJens Wiklander  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20*1d171f95SJens Wiklander  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21*1d171f95SJens Wiklander  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22*1d171f95SJens Wiklander  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*1d171f95SJens Wiklander  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24*1d171f95SJens Wiklander  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25*1d171f95SJens Wiklander  * POSSIBILITY OF SUCH DAMAGE.
26*1d171f95SJens Wiklander  */
27*1d171f95SJens Wiklander 
28*1d171f95SJens Wiklander #include <assert.h>
29*1d171f95SJens Wiklander #include <compiler.h>
30*1d171f95SJens Wiklander #include <kernel/panic.h>
31*1d171f95SJens Wiklander #include <kernel/asan.h>
32*1d171f95SJens Wiklander #include <string.h>
33*1d171f95SJens Wiklander #include <types_ext.h>
34*1d171f95SJens Wiklander #include <util.h>
35*1d171f95SJens Wiklander #include <trace.h>
36*1d171f95SJens Wiklander 
37*1d171f95SJens Wiklander struct asan_source_location {
38*1d171f95SJens Wiklander 	const char *file_name;
39*1d171f95SJens Wiklander 	int line_no;
40*1d171f95SJens Wiklander 	int column_no;
41*1d171f95SJens Wiklander };
42*1d171f95SJens Wiklander 
43*1d171f95SJens Wiklander struct asan_global {
44*1d171f95SJens Wiklander 	uintptr_t beg;
45*1d171f95SJens Wiklander 	uintptr_t size;
46*1d171f95SJens Wiklander 	uintptr_t size_with_redzone;
47*1d171f95SJens Wiklander 	const char *name;
48*1d171f95SJens Wiklander 	const char *module_name;
49*1d171f95SJens Wiklander 	uintptr_t has_dynamic_init;
50*1d171f95SJens Wiklander 	struct asan_source_location *location;
51*1d171f95SJens Wiklander };
52*1d171f95SJens Wiklander 
53*1d171f95SJens Wiklander static vaddr_t asan_va_base;
54*1d171f95SJens Wiklander static size_t asan_va_size;
55*1d171f95SJens Wiklander static bool asan_active;
56*1d171f95SJens Wiklander 
57*1d171f95SJens Wiklander static int8_t *va_to_shadow(void *va)
58*1d171f95SJens Wiklander {
59*1d171f95SJens Wiklander 	vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET;
60*1d171f95SJens Wiklander 
61*1d171f95SJens Wiklander 	return (int8_t *)sa;
62*1d171f95SJens Wiklander }
63*1d171f95SJens Wiklander 
64*1d171f95SJens Wiklander static size_t va_range_to_shadow_size(void *begin, void *end)
65*1d171f95SJens Wiklander {
66*1d171f95SJens Wiklander 	return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE;
67*1d171f95SJens Wiklander }
68*1d171f95SJens Wiklander 
69*1d171f95SJens Wiklander static bool va_range_inside_shadow(void *begin, void *end)
70*1d171f95SJens Wiklander {
71*1d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
72*1d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
73*1d171f95SJens Wiklander 
74*1d171f95SJens Wiklander 	if (b >= e)
75*1d171f95SJens Wiklander 		return false;
76*1d171f95SJens Wiklander 	return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size));
77*1d171f95SJens Wiklander }
78*1d171f95SJens Wiklander 
79*1d171f95SJens Wiklander static bool va_range_outside_shadow(void *begin, void *end)
80*1d171f95SJens Wiklander {
81*1d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
82*1d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
83*1d171f95SJens Wiklander 
84*1d171f95SJens Wiklander 	if (b >= e)
85*1d171f95SJens Wiklander 		return false;
86*1d171f95SJens Wiklander 	return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size));
87*1d171f95SJens Wiklander }
88*1d171f95SJens Wiklander 
89*1d171f95SJens Wiklander static size_t va_misalignment(void *va)
90*1d171f95SJens Wiklander {
91*1d171f95SJens Wiklander 	return (vaddr_t)va & ASAN_BLOCK_MASK;
92*1d171f95SJens Wiklander }
93*1d171f95SJens Wiklander 
94*1d171f95SJens Wiklander static bool va_is_well_aligned(void *va)
95*1d171f95SJens Wiklander {
96*1d171f95SJens Wiklander 	return !va_misalignment(va);
97*1d171f95SJens Wiklander }
98*1d171f95SJens Wiklander 
99*1d171f95SJens Wiklander void asan_set_shadowed(void *begin, void *end)
100*1d171f95SJens Wiklander {
101*1d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
102*1d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
103*1d171f95SJens Wiklander 
104*1d171f95SJens Wiklander 	assert(!asan_va_base);
105*1d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
106*1d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
107*1d171f95SJens Wiklander 	assert(b < e);
108*1d171f95SJens Wiklander 
109*1d171f95SJens Wiklander 	asan_va_base = b;
110*1d171f95SJens Wiklander 	asan_va_size = e - b;
111*1d171f95SJens Wiklander }
112*1d171f95SJens Wiklander 
113*1d171f95SJens Wiklander void asan_tag_no_access(void *begin, void *end)
114*1d171f95SJens Wiklander {
115*1d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
116*1d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
117*1d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
118*1d171f95SJens Wiklander 
119*1d171f95SJens Wiklander 	memset(va_to_shadow(begin), ASAN_DATA_RED_ZONE,
120*1d171f95SJens Wiklander 	       va_range_to_shadow_size(begin, end));
121*1d171f95SJens Wiklander }
122*1d171f95SJens Wiklander 
123*1d171f95SJens Wiklander void asan_tag_access(void *begin, void *end)
124*1d171f95SJens Wiklander {
125*1d171f95SJens Wiklander 	if (!asan_va_base)
126*1d171f95SJens Wiklander 		return;
127*1d171f95SJens Wiklander 
128*1d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
129*1d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
130*1d171f95SJens Wiklander 
131*1d171f95SJens Wiklander 	memset(va_to_shadow(begin), 0, va_range_to_shadow_size(begin, end));
132*1d171f95SJens Wiklander 	if (!va_is_well_aligned(end))
133*1d171f95SJens Wiklander 		*va_to_shadow(end) = ASAN_BLOCK_SIZE - va_misalignment(end);
134*1d171f95SJens Wiklander }
135*1d171f95SJens Wiklander 
136*1d171f95SJens Wiklander void asan_tag_heap_free(void *begin, void *end)
137*1d171f95SJens Wiklander {
138*1d171f95SJens Wiklander 	if (!asan_va_base)
139*1d171f95SJens Wiklander 		return;
140*1d171f95SJens Wiklander 
141*1d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
142*1d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
143*1d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
144*1d171f95SJens Wiklander 
145*1d171f95SJens Wiklander 	memset(va_to_shadow(begin), ASAN_HEAP_RED_ZONE,
146*1d171f95SJens Wiklander 	       va_range_to_shadow_size(begin, end));
147*1d171f95SJens Wiklander }
148*1d171f95SJens Wiklander 
149*1d171f95SJens Wiklander void asan_start(void)
150*1d171f95SJens Wiklander {
151*1d171f95SJens Wiklander 	assert(asan_va_base && !asan_active);
152*1d171f95SJens Wiklander 	asan_active = true;
153*1d171f95SJens Wiklander }
154*1d171f95SJens Wiklander 
155*1d171f95SJens Wiklander static void check_access(vaddr_t addr, size_t size)
156*1d171f95SJens Wiklander {
157*1d171f95SJens Wiklander 	void *begin = (void *)addr;
158*1d171f95SJens Wiklander 	void *end = (void *)(addr + size);
159*1d171f95SJens Wiklander 	int8_t *a;
160*1d171f95SJens Wiklander 	int8_t *e;
161*1d171f95SJens Wiklander 
162*1d171f95SJens Wiklander 	if (!asan_active || !size)
163*1d171f95SJens Wiklander 		return;
164*1d171f95SJens Wiklander 	if (va_range_outside_shadow(begin, end))
165*1d171f95SJens Wiklander 		return;
166*1d171f95SJens Wiklander 	/*
167*1d171f95SJens Wiklander 	 * If it isn't outside it has to be completely inside or there's a
168*1d171f95SJens Wiklander 	 * problem.
169*1d171f95SJens Wiklander 	 */
170*1d171f95SJens Wiklander 	if (!va_range_inside_shadow(begin, end))
171*1d171f95SJens Wiklander 		panic();
172*1d171f95SJens Wiklander 
173*1d171f95SJens Wiklander 	e = va_to_shadow(end);
174*1d171f95SJens Wiklander 	for (a = va_to_shadow(begin); a != e; a++)
175*1d171f95SJens Wiklander 		if (*a < 0)
176*1d171f95SJens Wiklander 			panic();
177*1d171f95SJens Wiklander 
178*1d171f95SJens Wiklander 	if (!va_is_well_aligned(end) &&
179*1d171f95SJens Wiklander 	    va_misalignment(end) > (size_t)(*e - ASAN_BLOCK_SIZE))
180*1d171f95SJens Wiklander 		panic();
181*1d171f95SJens Wiklander }
182*1d171f95SJens Wiklander 
183*1d171f95SJens Wiklander static void check_load(vaddr_t addr, size_t size)
184*1d171f95SJens Wiklander {
185*1d171f95SJens Wiklander 	check_access(addr, size);
186*1d171f95SJens Wiklander }
187*1d171f95SJens Wiklander 
188*1d171f95SJens Wiklander static void check_store(vaddr_t addr, size_t size)
189*1d171f95SJens Wiklander {
190*1d171f95SJens Wiklander 	check_access(addr, size);
191*1d171f95SJens Wiklander }
192*1d171f95SJens Wiklander 
193*1d171f95SJens Wiklander static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused)
194*1d171f95SJens Wiklander {
195*1d171f95SJens Wiklander 	panic();
196*1d171f95SJens Wiklander }
197*1d171f95SJens Wiklander 
198*1d171f95SJens Wiklander static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused)
199*1d171f95SJens Wiklander {
200*1d171f95SJens Wiklander 	panic();
201*1d171f95SJens Wiklander }
202*1d171f95SJens Wiklander 
203*1d171f95SJens Wiklander 
204*1d171f95SJens Wiklander 
205*1d171f95SJens Wiklander #define DEFINE_ASAN_FUNC(type, size)				\
206*1d171f95SJens Wiklander 	void __asan_##type##size(vaddr_t addr);			\
207*1d171f95SJens Wiklander 	void __asan_##type##size(vaddr_t addr)			\
208*1d171f95SJens Wiklander 	{ check_##type(addr, size); }				\
209*1d171f95SJens Wiklander 	void __asan_##type##size##_noabort(vaddr_t addr);	\
210*1d171f95SJens Wiklander 	void __asan_##type##size##_noabort(vaddr_t addr)	\
211*1d171f95SJens Wiklander 	{ check_##type(addr, size); }				\
212*1d171f95SJens Wiklander 	void __asan_report_##type##size##_noabort(vaddr_t addr);\
213*1d171f95SJens Wiklander 	void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \
214*1d171f95SJens Wiklander 	{ report_##type(addr, size); }
215*1d171f95SJens Wiklander 
216*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 1)
217*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 2)
218*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 4)
219*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 8)
220*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 16)
221*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 1)
222*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 2)
223*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 4)
224*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 8)
225*1d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 16)
226*1d171f95SJens Wiklander 
227*1d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size);
228*1d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size)
229*1d171f95SJens Wiklander {
230*1d171f95SJens Wiklander 	check_load(addr, size);
231*1d171f95SJens Wiklander }
232*1d171f95SJens Wiklander 
233*1d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size);
234*1d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size)
235*1d171f95SJens Wiklander {
236*1d171f95SJens Wiklander 	check_store(addr, size);
237*1d171f95SJens Wiklander }
238*1d171f95SJens Wiklander 
239*1d171f95SJens Wiklander void __asan_report_load_n_noabort(vaddr_t addr, size_t size);
240*1d171f95SJens Wiklander void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size)
241*1d171f95SJens Wiklander {
242*1d171f95SJens Wiklander 	report_load(addr, size);
243*1d171f95SJens Wiklander }
244*1d171f95SJens Wiklander 
245*1d171f95SJens Wiklander void __asan_report_store_n_noabort(vaddr_t addr, size_t size);
246*1d171f95SJens Wiklander void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size)
247*1d171f95SJens Wiklander {
248*1d171f95SJens Wiklander 	report_store(addr, size);
249*1d171f95SJens Wiklander }
250*1d171f95SJens Wiklander 
251*1d171f95SJens Wiklander void __asan_handle_no_return(void);
252*1d171f95SJens Wiklander void __noreturn __asan_handle_no_return(void)
253*1d171f95SJens Wiklander {
254*1d171f95SJens Wiklander 	panic();
255*1d171f95SJens Wiklander }
256*1d171f95SJens Wiklander 
257*1d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size);
258*1d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size)
259*1d171f95SJens Wiklander {
260*1d171f95SJens Wiklander 	size_t n;
261*1d171f95SJens Wiklander 
262*1d171f95SJens Wiklander 	for (n = 0; n < size; n++)
263*1d171f95SJens Wiklander 		asan_tag_access((void *)globals[n].beg,
264*1d171f95SJens Wiklander 				(void *)(globals[n].beg + globals[n].size));
265*1d171f95SJens Wiklander }
266*1d171f95SJens Wiklander 
267*1d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals, size_t size);
268*1d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals __unused,
269*1d171f95SJens Wiklander 			       size_t size __unused)
270*1d171f95SJens Wiklander {
271*1d171f95SJens Wiklander }
272