xref: /optee_os/lib/libutils/ext/asan.c (revision d6d1731bef3d306080076b5a9be15682e353241a)
1*d6d1731bSAleksandr Iashchenko // SPDX-License-Identifier: BSD-2-Clause
2*d6d1731bSAleksandr Iashchenko /*
3*d6d1731bSAleksandr Iashchenko  * Copyright (c) 2016, Linaro Limited
4*d6d1731bSAleksandr Iashchenko  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
5*d6d1731bSAleksandr Iashchenko  */
6*d6d1731bSAleksandr Iashchenko 
7*d6d1731bSAleksandr Iashchenko #include <asan.h>
8*d6d1731bSAleksandr Iashchenko #include <assert.h>
9*d6d1731bSAleksandr Iashchenko #include <compiler.h>
10*d6d1731bSAleksandr Iashchenko #include <keep.h>
11*d6d1731bSAleksandr Iashchenko #include <kernel/panic.h>
12*d6d1731bSAleksandr Iashchenko #include <printk.h>
13*d6d1731bSAleksandr Iashchenko #include <setjmp.h>
14*d6d1731bSAleksandr Iashchenko #include <string.h>
15*d6d1731bSAleksandr Iashchenko #include <trace.h>
16*d6d1731bSAleksandr Iashchenko #include <types_ext.h>
17*d6d1731bSAleksandr Iashchenko #include <util.h>
18*d6d1731bSAleksandr Iashchenko 
19*d6d1731bSAleksandr Iashchenko #if __GCC_VERSION >= 70000
20*d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 7
21*d6d1731bSAleksandr Iashchenko #else
22*d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 6
23*d6d1731bSAleksandr Iashchenko #endif
24*d6d1731bSAleksandr Iashchenko 
25*d6d1731bSAleksandr Iashchenko struct asan_source_location {
26*d6d1731bSAleksandr Iashchenko 	const char *file_name;
27*d6d1731bSAleksandr Iashchenko 	int line_no;
28*d6d1731bSAleksandr Iashchenko 	int column_no;
29*d6d1731bSAleksandr Iashchenko };
30*d6d1731bSAleksandr Iashchenko 
31*d6d1731bSAleksandr Iashchenko struct asan_global {
32*d6d1731bSAleksandr Iashchenko 	uintptr_t beg;
33*d6d1731bSAleksandr Iashchenko 	uintptr_t size;
34*d6d1731bSAleksandr Iashchenko 	uintptr_t size_with_redzone;
35*d6d1731bSAleksandr Iashchenko 	const char *name;
36*d6d1731bSAleksandr Iashchenko 	const char *module_name;
37*d6d1731bSAleksandr Iashchenko 	uintptr_t has_dynamic_init;
38*d6d1731bSAleksandr Iashchenko 	struct asan_source_location *location;
39*d6d1731bSAleksandr Iashchenko #if ASAN_ABI_VERSION >= 7
40*d6d1731bSAleksandr Iashchenko 	uintptr_t odr_indicator;
41*d6d1731bSAleksandr Iashchenko #endif
42*d6d1731bSAleksandr Iashchenko };
43*d6d1731bSAleksandr Iashchenko 
44*d6d1731bSAleksandr Iashchenko static vaddr_t asan_va_base;
45*d6d1731bSAleksandr Iashchenko static size_t asan_va_size;
46*d6d1731bSAleksandr Iashchenko static bool asan_active;
47*d6d1731bSAleksandr Iashchenko static asan_panic_cb_t asan_panic_cb = asan_panic;
48*d6d1731bSAleksandr Iashchenko 
49*d6d1731bSAleksandr Iashchenko static bool addr_crosses_scale_boundary(vaddr_t addr, size_t size)
50*d6d1731bSAleksandr Iashchenko {
51*d6d1731bSAleksandr Iashchenko 	return (addr >> ASAN_BLOCK_SHIFT) !=
52*d6d1731bSAleksandr Iashchenko 	       ((addr + size - 1) >> ASAN_BLOCK_SHIFT);
53*d6d1731bSAleksandr Iashchenko }
54*d6d1731bSAleksandr Iashchenko 
55*d6d1731bSAleksandr Iashchenko static int8_t *va_to_shadow(const void *va)
56*d6d1731bSAleksandr Iashchenko {
57*d6d1731bSAleksandr Iashchenko 	vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET;
58*d6d1731bSAleksandr Iashchenko 
59*d6d1731bSAleksandr Iashchenko 	return (int8_t *)sa;
60*d6d1731bSAleksandr Iashchenko }
61*d6d1731bSAleksandr Iashchenko 
62*d6d1731bSAleksandr Iashchenko static size_t va_range_to_shadow_size(const void *begin, const void *end)
63*d6d1731bSAleksandr Iashchenko {
64*d6d1731bSAleksandr Iashchenko 	return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE;
65*d6d1731bSAleksandr Iashchenko }
66*d6d1731bSAleksandr Iashchenko 
67*d6d1731bSAleksandr Iashchenko static bool va_range_inside_shadow(const void *begin, const void *end)
68*d6d1731bSAleksandr Iashchenko {
69*d6d1731bSAleksandr Iashchenko 	vaddr_t b = (vaddr_t)begin;
70*d6d1731bSAleksandr Iashchenko 	vaddr_t e = (vaddr_t)end;
71*d6d1731bSAleksandr Iashchenko 
72*d6d1731bSAleksandr Iashchenko 	if (b >= e)
73*d6d1731bSAleksandr Iashchenko 		return false;
74*d6d1731bSAleksandr Iashchenko 	return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size));
75*d6d1731bSAleksandr Iashchenko }
76*d6d1731bSAleksandr Iashchenko 
77*d6d1731bSAleksandr Iashchenko static bool va_range_outside_shadow(const void *begin, const void *end)
78*d6d1731bSAleksandr Iashchenko {
79*d6d1731bSAleksandr Iashchenko 	vaddr_t b = (vaddr_t)begin;
80*d6d1731bSAleksandr Iashchenko 	vaddr_t e = (vaddr_t)end;
81*d6d1731bSAleksandr Iashchenko 
82*d6d1731bSAleksandr Iashchenko 	if (b >= e)
83*d6d1731bSAleksandr Iashchenko 		return false;
84*d6d1731bSAleksandr Iashchenko 	return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size));
85*d6d1731bSAleksandr Iashchenko }
86*d6d1731bSAleksandr Iashchenko 
87*d6d1731bSAleksandr Iashchenko static size_t va_misalignment(const void *va)
88*d6d1731bSAleksandr Iashchenko {
89*d6d1731bSAleksandr Iashchenko 	return (vaddr_t)va & ASAN_BLOCK_MASK;
90*d6d1731bSAleksandr Iashchenko }
91*d6d1731bSAleksandr Iashchenko 
92*d6d1731bSAleksandr Iashchenko static bool va_is_well_aligned(const void *va)
93*d6d1731bSAleksandr Iashchenko {
94*d6d1731bSAleksandr Iashchenko 	return !va_misalignment(va);
95*d6d1731bSAleksandr Iashchenko }
96*d6d1731bSAleksandr Iashchenko 
97*d6d1731bSAleksandr Iashchenko void asan_set_shadowed(const void *begin, const void *end)
98*d6d1731bSAleksandr Iashchenko {
99*d6d1731bSAleksandr Iashchenko 	vaddr_t b = (vaddr_t)begin;
100*d6d1731bSAleksandr Iashchenko 	vaddr_t e = (vaddr_t)end;
101*d6d1731bSAleksandr Iashchenko 
102*d6d1731bSAleksandr Iashchenko 	assert(!asan_va_base);
103*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
104*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
105*d6d1731bSAleksandr Iashchenko 	assert(b < e);
106*d6d1731bSAleksandr Iashchenko 
107*d6d1731bSAleksandr Iashchenko 	asan_va_base = b;
108*d6d1731bSAleksandr Iashchenko 	asan_va_size = e - b;
109*d6d1731bSAleksandr Iashchenko }
110*d6d1731bSAleksandr Iashchenko 
111*d6d1731bSAleksandr Iashchenko void asan_tag_no_access(const void *begin, const void *end)
112*d6d1731bSAleksandr Iashchenko {
113*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
114*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
115*d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
116*d6d1731bSAleksandr Iashchenko 
117*d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), ASAN_DATA_RED_ZONE,
118*d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
119*d6d1731bSAleksandr Iashchenko }
120*d6d1731bSAleksandr Iashchenko 
121*d6d1731bSAleksandr Iashchenko void asan_tag_access(const void *begin, const void *end)
122*d6d1731bSAleksandr Iashchenko {
123*d6d1731bSAleksandr Iashchenko 	if (!asan_va_base || (begin == end))
124*d6d1731bSAleksandr Iashchenko 		return;
125*d6d1731bSAleksandr Iashchenko 
126*d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
127*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
128*d6d1731bSAleksandr Iashchenko 
129*d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), 0,
130*d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
131*d6d1731bSAleksandr Iashchenko 	if (!va_is_well_aligned(end))
132*d6d1731bSAleksandr Iashchenko 		*va_to_shadow(end) = va_misalignment(end);
133*d6d1731bSAleksandr Iashchenko }
134*d6d1731bSAleksandr Iashchenko 
135*d6d1731bSAleksandr Iashchenko void asan_tag_heap_free(const void *begin, const void *end)
136*d6d1731bSAleksandr Iashchenko {
137*d6d1731bSAleksandr Iashchenko 	if (!asan_va_base)
138*d6d1731bSAleksandr Iashchenko 		return;
139*d6d1731bSAleksandr Iashchenko 
140*d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
141*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
142*d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
143*d6d1731bSAleksandr Iashchenko 
144*d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), ASAN_HEAP_RED_ZONE,
145*d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
146*d6d1731bSAleksandr Iashchenko }
147*d6d1731bSAleksandr Iashchenko 
148*d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall void *asan_memset_unchecked(void *s, int c, size_t n)
149*d6d1731bSAleksandr Iashchenko {
150*d6d1731bSAleksandr Iashchenko 	uint8_t *b = s;
151*d6d1731bSAleksandr Iashchenko 	size_t m;
152*d6d1731bSAleksandr Iashchenko 
153*d6d1731bSAleksandr Iashchenko 	for (m = 0; m < n; m++)
154*d6d1731bSAleksandr Iashchenko 		b[m] = c;
155*d6d1731bSAleksandr Iashchenko 
156*d6d1731bSAleksandr Iashchenko 	return s;
157*d6d1731bSAleksandr Iashchenko }
158*d6d1731bSAleksandr Iashchenko 
159*d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall
160*d6d1731bSAleksandr Iashchenko void *asan_memcpy_unchecked(void *__restrict dst, const void *__restrict src,
161*d6d1731bSAleksandr Iashchenko 			    size_t len)
162*d6d1731bSAleksandr Iashchenko {
163*d6d1731bSAleksandr Iashchenko 	uint8_t *__restrict d = dst;
164*d6d1731bSAleksandr Iashchenko 	const uint8_t *__restrict s = src;
165*d6d1731bSAleksandr Iashchenko 	size_t n;
166*d6d1731bSAleksandr Iashchenko 
167*d6d1731bSAleksandr Iashchenko 	for (n = 0; n < len; n++)
168*d6d1731bSAleksandr Iashchenko 		d[n] = s[n];
169*d6d1731bSAleksandr Iashchenko 
170*d6d1731bSAleksandr Iashchenko 	return dst;
171*d6d1731bSAleksandr Iashchenko }
172*d6d1731bSAleksandr Iashchenko 
173*d6d1731bSAleksandr Iashchenko void asan_start(void)
174*d6d1731bSAleksandr Iashchenko {
175*d6d1731bSAleksandr Iashchenko 	assert(asan_va_base && !asan_active);
176*d6d1731bSAleksandr Iashchenko 	asan_active = true;
177*d6d1731bSAleksandr Iashchenko }
178*d6d1731bSAleksandr Iashchenko 
179*d6d1731bSAleksandr Iashchenko void __noreturn asan_panic(void)
180*d6d1731bSAleksandr Iashchenko {
181*d6d1731bSAleksandr Iashchenko 	panic();
182*d6d1731bSAleksandr Iashchenko }
183*d6d1731bSAleksandr Iashchenko 
184*d6d1731bSAleksandr Iashchenko void asan_set_panic_cb(asan_panic_cb_t panic_cb)
185*d6d1731bSAleksandr Iashchenko {
186*d6d1731bSAleksandr Iashchenko 	asan_panic_cb = panic_cb;
187*d6d1731bSAleksandr Iashchenko }
188*d6d1731bSAleksandr Iashchenko 
189*d6d1731bSAleksandr Iashchenko static void asan_report(vaddr_t addr, size_t size)
190*d6d1731bSAleksandr Iashchenko {
191*d6d1731bSAleksandr Iashchenko #ifdef KASAN_DUMP_SHADOW
192*d6d1731bSAleksandr Iashchenko 	char buf[128] = {0};
193*d6d1731bSAleksandr Iashchenko 	int r = 0, rc = 0;
194*d6d1731bSAleksandr Iashchenko 	vaddr_t b = 0, e = 0, saddr = 0;
195*d6d1731bSAleksandr Iashchenko 
196*d6d1731bSAleksandr Iashchenko 	b = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) - ASAN_BLOCK_SIZE;
197*d6d1731bSAleksandr Iashchenko 	e = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) + ASAN_BLOCK_SIZE;
198*d6d1731bSAleksandr Iashchenko 
199*d6d1731bSAleksandr Iashchenko 	/* Print shadow map nearby */
200*d6d1731bSAleksandr Iashchenko 	if (va_range_inside_shadow((void *)b, (void *)e)) {
201*d6d1731bSAleksandr Iashchenko 		rc = snprintk(buf + r, sizeof(buf) - r, "%lx: ", b);
202*d6d1731bSAleksandr Iashchenko 		assert(rc > 0);
203*d6d1731bSAleksandr Iashchenko 		r += rc;
204*d6d1731bSAleksandr Iashchenko 		for (saddr = b; saddr <= e; saddr += ASAN_BLOCK_SIZE) {
205*d6d1731bSAleksandr Iashchenko 			int8_t *sbyte = va_to_shadow((void *)saddr);
206*d6d1731bSAleksandr Iashchenko 
207*d6d1731bSAleksandr Iashchenko 			rc = snprintk(buf + r, sizeof(buf) - r,
208*d6d1731bSAleksandr Iashchenko 				      "0x%02x ", (uint8_t)*sbyte);
209*d6d1731bSAleksandr Iashchenko 			assert(rc > 0);
210*d6d1731bSAleksandr Iashchenko 			r += rc;
211*d6d1731bSAleksandr Iashchenko 		}
212*d6d1731bSAleksandr Iashchenko 		EMSG("%s", buf);
213*d6d1731bSAleksandr Iashchenko 	}
214*d6d1731bSAleksandr Iashchenko #endif
215*d6d1731bSAleksandr Iashchenko 	EMSG("[ASAN]: access violation, addr: %lx size: %zu\n",
216*d6d1731bSAleksandr Iashchenko 	     addr, size);
217*d6d1731bSAleksandr Iashchenko 
218*d6d1731bSAleksandr Iashchenko 	asan_panic_cb();
219*d6d1731bSAleksandr Iashchenko }
220*d6d1731bSAleksandr Iashchenko 
221*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_1byte_isvalid(vaddr_t addr)
222*d6d1731bSAleksandr Iashchenko {
223*d6d1731bSAleksandr Iashchenko 	int8_t last = (addr & ASAN_BLOCK_MASK) + 1;
224*d6d1731bSAleksandr Iashchenko 	int8_t *byte = va_to_shadow((void *)addr);
225*d6d1731bSAleksandr Iashchenko 
226*d6d1731bSAleksandr Iashchenko 	if (*byte == 0 || last <= *byte)
227*d6d1731bSAleksandr Iashchenko 		return true;
228*d6d1731bSAleksandr Iashchenko 
229*d6d1731bSAleksandr Iashchenko 	return false;
230*d6d1731bSAleksandr Iashchenko }
231*d6d1731bSAleksandr Iashchenko 
232*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_2byte_isvalid(vaddr_t addr)
233*d6d1731bSAleksandr Iashchenko {
234*d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 2)) {
235*d6d1731bSAleksandr Iashchenko 		return (asan_shadow_1byte_isvalid(addr) &&
236*d6d1731bSAleksandr Iashchenko 			asan_shadow_1byte_isvalid(addr + 1));
237*d6d1731bSAleksandr Iashchenko 	} else {
238*d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 1) & ASAN_BLOCK_MASK) + 1;
239*d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
240*d6d1731bSAleksandr Iashchenko 
241*d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
242*d6d1731bSAleksandr Iashchenko 			return true;
243*d6d1731bSAleksandr Iashchenko 
244*d6d1731bSAleksandr Iashchenko 		return false;
245*d6d1731bSAleksandr Iashchenko 	}
246*d6d1731bSAleksandr Iashchenko }
247*d6d1731bSAleksandr Iashchenko 
248*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_4byte_isvalid(vaddr_t addr)
249*d6d1731bSAleksandr Iashchenko {
250*d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 4)) {
251*d6d1731bSAleksandr Iashchenko 		return (asan_shadow_2byte_isvalid(addr) &&
252*d6d1731bSAleksandr Iashchenko 			asan_shadow_2byte_isvalid(addr + 2));
253*d6d1731bSAleksandr Iashchenko 	} else {
254*d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 3) & ASAN_BLOCK_MASK) + 1;
255*d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
256*d6d1731bSAleksandr Iashchenko 
257*d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
258*d6d1731bSAleksandr Iashchenko 			return true;
259*d6d1731bSAleksandr Iashchenko 
260*d6d1731bSAleksandr Iashchenko 		return false;
261*d6d1731bSAleksandr Iashchenko 	}
262*d6d1731bSAleksandr Iashchenko }
263*d6d1731bSAleksandr Iashchenko 
264*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_8byte_isvalid(vaddr_t addr)
265*d6d1731bSAleksandr Iashchenko {
266*d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 8)) {
267*d6d1731bSAleksandr Iashchenko 		return (asan_shadow_4byte_isvalid(addr) &&
268*d6d1731bSAleksandr Iashchenko 			asan_shadow_4byte_isvalid(addr + 4));
269*d6d1731bSAleksandr Iashchenko 	} else {
270*d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 7) & ASAN_BLOCK_MASK) + 1;
271*d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
272*d6d1731bSAleksandr Iashchenko 
273*d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
274*d6d1731bSAleksandr Iashchenko 			return true;
275*d6d1731bSAleksandr Iashchenko 
276*d6d1731bSAleksandr Iashchenko 		return false;
277*d6d1731bSAleksandr Iashchenko 	}
278*d6d1731bSAleksandr Iashchenko }
279*d6d1731bSAleksandr Iashchenko 
280*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_Nbyte_isvalid(vaddr_t addr,
281*d6d1731bSAleksandr Iashchenko 						      size_t size)
282*d6d1731bSAleksandr Iashchenko {
283*d6d1731bSAleksandr Iashchenko 	size_t i = 0;
284*d6d1731bSAleksandr Iashchenko 
285*d6d1731bSAleksandr Iashchenko 	for (; i < size; i++) {
286*d6d1731bSAleksandr Iashchenko 		if (!asan_shadow_1byte_isvalid(addr + i))
287*d6d1731bSAleksandr Iashchenko 			return false;
288*d6d1731bSAleksandr Iashchenko 	}
289*d6d1731bSAleksandr Iashchenko 
290*d6d1731bSAleksandr Iashchenko 	return true;
291*d6d1731bSAleksandr Iashchenko }
292*d6d1731bSAleksandr Iashchenko 
293*d6d1731bSAleksandr Iashchenko static __always_inline void check_access(vaddr_t addr, size_t size)
294*d6d1731bSAleksandr Iashchenko {
295*d6d1731bSAleksandr Iashchenko 	bool valid = false;
296*d6d1731bSAleksandr Iashchenko 	void *begin = (void *)addr;
297*d6d1731bSAleksandr Iashchenko 	void *end = (void *)(addr + size);
298*d6d1731bSAleksandr Iashchenko 
299*d6d1731bSAleksandr Iashchenko 	if (!asan_active)
300*d6d1731bSAleksandr Iashchenko 		return;
301*d6d1731bSAleksandr Iashchenko 	if (size == 0)
302*d6d1731bSAleksandr Iashchenko 		return;
303*d6d1731bSAleksandr Iashchenko 	if (va_range_outside_shadow(begin, end))
304*d6d1731bSAleksandr Iashchenko 		return;
305*d6d1731bSAleksandr Iashchenko 	/*
306*d6d1731bSAleksandr Iashchenko 	 * If it isn't outside it has to be completely inside or there's a
307*d6d1731bSAleksandr Iashchenko 	 * problem.
308*d6d1731bSAleksandr Iashchenko 	 */
309*d6d1731bSAleksandr Iashchenko 	if (!va_range_inside_shadow(begin, end))
310*d6d1731bSAleksandr Iashchenko 		panic();
311*d6d1731bSAleksandr Iashchenko 
312*d6d1731bSAleksandr Iashchenko 	if (__builtin_constant_p(size)) {
313*d6d1731bSAleksandr Iashchenko 		switch (size) {
314*d6d1731bSAleksandr Iashchenko 		case 1:
315*d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_1byte_isvalid(addr);
316*d6d1731bSAleksandr Iashchenko 			break;
317*d6d1731bSAleksandr Iashchenko 		case 2:
318*d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_2byte_isvalid(addr);
319*d6d1731bSAleksandr Iashchenko 			break;
320*d6d1731bSAleksandr Iashchenko 		case 4:
321*d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_4byte_isvalid(addr);
322*d6d1731bSAleksandr Iashchenko 			break;
323*d6d1731bSAleksandr Iashchenko 		case 8:
324*d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_8byte_isvalid(addr);
325*d6d1731bSAleksandr Iashchenko 			break;
326*d6d1731bSAleksandr Iashchenko 		default:
327*d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_Nbyte_isvalid(addr, size);
328*d6d1731bSAleksandr Iashchenko 			break;
329*d6d1731bSAleksandr Iashchenko 		}
330*d6d1731bSAleksandr Iashchenko 	} else {
331*d6d1731bSAleksandr Iashchenko 		valid = asan_shadow_Nbyte_isvalid(addr, size);
332*d6d1731bSAleksandr Iashchenko 	}
333*d6d1731bSAleksandr Iashchenko 
334*d6d1731bSAleksandr Iashchenko 	if (!valid)
335*d6d1731bSAleksandr Iashchenko 		asan_report(addr, size);
336*d6d1731bSAleksandr Iashchenko }
337*d6d1731bSAleksandr Iashchenko 
338*d6d1731bSAleksandr Iashchenko static __always_inline void check_load(vaddr_t addr, size_t size)
339*d6d1731bSAleksandr Iashchenko {
340*d6d1731bSAleksandr Iashchenko 	check_access(addr, size);
341*d6d1731bSAleksandr Iashchenko }
342*d6d1731bSAleksandr Iashchenko 
343*d6d1731bSAleksandr Iashchenko static __always_inline void check_store(vaddr_t addr, size_t size)
344*d6d1731bSAleksandr Iashchenko {
345*d6d1731bSAleksandr Iashchenko 	check_access(addr, size);
346*d6d1731bSAleksandr Iashchenko }
347*d6d1731bSAleksandr Iashchenko 
348*d6d1731bSAleksandr Iashchenko static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused)
349*d6d1731bSAleksandr Iashchenko {
350*d6d1731bSAleksandr Iashchenko 	panic();
351*d6d1731bSAleksandr Iashchenko }
352*d6d1731bSAleksandr Iashchenko 
353*d6d1731bSAleksandr Iashchenko static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused)
354*d6d1731bSAleksandr Iashchenko {
355*d6d1731bSAleksandr Iashchenko 	panic();
356*d6d1731bSAleksandr Iashchenko }
357*d6d1731bSAleksandr Iashchenko 
358*d6d1731bSAleksandr Iashchenko 
359*d6d1731bSAleksandr Iashchenko 
360*d6d1731bSAleksandr Iashchenko #define DEFINE_ASAN_FUNC(type, size)				\
361*d6d1731bSAleksandr Iashchenko 	void __asan_##type##size(vaddr_t addr);			\
362*d6d1731bSAleksandr Iashchenko 	void __asan_##type##size(vaddr_t addr)			\
363*d6d1731bSAleksandr Iashchenko 	{ check_##type(addr, size); }				\
364*d6d1731bSAleksandr Iashchenko 	void __asan_##type##size##_noabort(vaddr_t addr);	\
365*d6d1731bSAleksandr Iashchenko 	void __asan_##type##size##_noabort(vaddr_t addr)	\
366*d6d1731bSAleksandr Iashchenko 	{ check_##type(addr, size); }				\
367*d6d1731bSAleksandr Iashchenko 	void __asan_report_##type##size##_noabort(vaddr_t addr);\
368*d6d1731bSAleksandr Iashchenko 	void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \
369*d6d1731bSAleksandr Iashchenko 	{ report_##type(addr, size); }
370*d6d1731bSAleksandr Iashchenko 
371*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 1)
372*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 2)
373*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 4)
374*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 8)
375*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 16)
376*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 1)
377*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 2)
378*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 4)
379*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 8)
380*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 16)
381*d6d1731bSAleksandr Iashchenko 
382*d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size);
383*d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size)
384*d6d1731bSAleksandr Iashchenko {
385*d6d1731bSAleksandr Iashchenko 	check_load(addr, size);
386*d6d1731bSAleksandr Iashchenko }
387*d6d1731bSAleksandr Iashchenko 
388*d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size);
389*d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size)
390*d6d1731bSAleksandr Iashchenko {
391*d6d1731bSAleksandr Iashchenko 	check_store(addr, size);
392*d6d1731bSAleksandr Iashchenko }
393*d6d1731bSAleksandr Iashchenko 
394*d6d1731bSAleksandr Iashchenko void __asan_report_load_n_noabort(vaddr_t addr, size_t size);
395*d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size)
396*d6d1731bSAleksandr Iashchenko {
397*d6d1731bSAleksandr Iashchenko 	report_load(addr, size);
398*d6d1731bSAleksandr Iashchenko }
399*d6d1731bSAleksandr Iashchenko 
400*d6d1731bSAleksandr Iashchenko void __asan_report_store_n_noabort(vaddr_t addr, size_t size);
401*d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size)
402*d6d1731bSAleksandr Iashchenko {
403*d6d1731bSAleksandr Iashchenko 	report_store(addr, size);
404*d6d1731bSAleksandr Iashchenko }
405*d6d1731bSAleksandr Iashchenko 
406*d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void);
407*d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void)
408*d6d1731bSAleksandr Iashchenko {
409*d6d1731bSAleksandr Iashchenko }
410*d6d1731bSAleksandr Iashchenko 
411*d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size);
412*d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size)
413*d6d1731bSAleksandr Iashchenko {
414*d6d1731bSAleksandr Iashchenko 	size_t n = 0;
415*d6d1731bSAleksandr Iashchenko 
416*d6d1731bSAleksandr Iashchenko 	for (n = 0; n < size; n++) {
417*d6d1731bSAleksandr Iashchenko 		vaddr_t begin = globals[n].beg;
418*d6d1731bSAleksandr Iashchenko 		vaddr_t end = begin + globals[n].size;
419*d6d1731bSAleksandr Iashchenko 		vaddr_t end_align = ROUNDUP(end, ASAN_BLOCK_SIZE);
420*d6d1731bSAleksandr Iashchenko 		vaddr_t end_rz = begin + globals[n].size_with_redzone;
421*d6d1731bSAleksandr Iashchenko 
422*d6d1731bSAleksandr Iashchenko 		asan_tag_access((void *)begin, (void *)end);
423*d6d1731bSAleksandr Iashchenko 		asan_tag_no_access((void *)end_align, (void *)end_rz);
424*d6d1731bSAleksandr Iashchenko 	}
425*d6d1731bSAleksandr Iashchenko }
426*d6d1731bSAleksandr Iashchenko DECLARE_KEEP_INIT(__asan_register_globals);
427*d6d1731bSAleksandr Iashchenko 
428*d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals, size_t size);
429*d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals __unused,
430*d6d1731bSAleksandr Iashchenko 			       size_t size __unused)
431*d6d1731bSAleksandr Iashchenko {
432*d6d1731bSAleksandr Iashchenko }
433*d6d1731bSAleksandr Iashchenko 
434*d6d1731bSAleksandr Iashchenko void asan_handle_longjmp(void *old_sp)
435*d6d1731bSAleksandr Iashchenko {
436*d6d1731bSAleksandr Iashchenko 	void *top = old_sp;
437*d6d1731bSAleksandr Iashchenko 	void *bottom = (void *)ROUNDDOWN((vaddr_t)&top,
438*d6d1731bSAleksandr Iashchenko 					 ASAN_BLOCK_SIZE);
439*d6d1731bSAleksandr Iashchenko 
440*d6d1731bSAleksandr Iashchenko 	asan_tag_access(bottom, top);
441*d6d1731bSAleksandr Iashchenko }
442