xref: /optee_os/lib/libutils/ext/asan.c (revision b8a0c52c847baf133e08f19f69759eb8a5de1a2c)
1d6d1731bSAleksandr Iashchenko // SPDX-License-Identifier: BSD-2-Clause
2d6d1731bSAleksandr Iashchenko /*
3d6d1731bSAleksandr Iashchenko  * Copyright (c) 2016, Linaro Limited
4d6d1731bSAleksandr Iashchenko  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
5d6d1731bSAleksandr Iashchenko  */
6d6d1731bSAleksandr Iashchenko 
7d6d1731bSAleksandr Iashchenko #include <asan.h>
8d6d1731bSAleksandr Iashchenko #include <assert.h>
9d6d1731bSAleksandr Iashchenko #include <compiler.h>
10d6d1731bSAleksandr Iashchenko #include <printk.h>
11d6d1731bSAleksandr Iashchenko #include <setjmp.h>
12d6d1731bSAleksandr Iashchenko #include <string.h>
13d6d1731bSAleksandr Iashchenko #include <trace.h>
14d6d1731bSAleksandr Iashchenko #include <types_ext.h>
15d6d1731bSAleksandr Iashchenko #include <util.h>
16d6d1731bSAleksandr Iashchenko 
17d6d1731bSAleksandr Iashchenko #if __GCC_VERSION >= 70000
18d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 7
19d6d1731bSAleksandr Iashchenko #else
20d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 6
21d6d1731bSAleksandr Iashchenko #endif
22d6d1731bSAleksandr Iashchenko 
234cafd8a3SAleksandr Iashchenko #if defined(__KERNEL__)
244cafd8a3SAleksandr Iashchenko # include <keep.h>
254cafd8a3SAleksandr Iashchenko # include <kernel/panic.h>
264cafd8a3SAleksandr Iashchenko #elif defined(__LDELF__)
274cafd8a3SAleksandr Iashchenko # include <ldelf_syscalls.h>
284cafd8a3SAleksandr Iashchenko # include <ldelf.h>
294cafd8a3SAleksandr Iashchenko #else
309f2dc7a1SAleksandr Iashchenko # include <tee_internal_api_extensions.h>
319f2dc7a1SAleksandr Iashchenko # include <utee_syscalls.h>
324cafd8a3SAleksandr Iashchenko #endif
334cafd8a3SAleksandr Iashchenko 
344cafd8a3SAleksandr Iashchenko #ifndef __KERNEL__
354cafd8a3SAleksandr Iashchenko /* Stub for non-kernel builds */
364cafd8a3SAleksandr Iashchenko #define DECLARE_KEEP_INIT(x)
374cafd8a3SAleksandr Iashchenko #endif
384cafd8a3SAleksandr Iashchenko 
394cafd8a3SAleksandr Iashchenko #ifndef SMALL_PAGE_SIZE
404cafd8a3SAleksandr Iashchenko #define SMALL_PAGE_SIZE 4096
414cafd8a3SAleksandr Iashchenko #endif
424cafd8a3SAleksandr Iashchenko 
43081fba0cSAleksandr Iashchenko #if TRACE_LEVEL >= TRACE_DEBUG
44081fba0cSAleksandr Iashchenko #define KASAN_DUMP_SHADOW
45081fba0cSAleksandr Iashchenko #endif
46081fba0cSAleksandr Iashchenko 
47d6d1731bSAleksandr Iashchenko struct asan_source_location {
48d6d1731bSAleksandr Iashchenko 	const char *file_name;
49d6d1731bSAleksandr Iashchenko 	int line_no;
50d6d1731bSAleksandr Iashchenko 	int column_no;
51d6d1731bSAleksandr Iashchenko };
52d6d1731bSAleksandr Iashchenko 
53d6d1731bSAleksandr Iashchenko struct asan_global {
54d6d1731bSAleksandr Iashchenko 	uintptr_t beg;
55d6d1731bSAleksandr Iashchenko 	uintptr_t size;
56d6d1731bSAleksandr Iashchenko 	uintptr_t size_with_redzone;
57d6d1731bSAleksandr Iashchenko 	const char *name;
58d6d1731bSAleksandr Iashchenko 	const char *module_name;
59d6d1731bSAleksandr Iashchenko 	uintptr_t has_dynamic_init;
60d6d1731bSAleksandr Iashchenko 	struct asan_source_location *location;
61d6d1731bSAleksandr Iashchenko #if ASAN_ABI_VERSION >= 7
62d6d1731bSAleksandr Iashchenko 	uintptr_t odr_indicator;
63d6d1731bSAleksandr Iashchenko #endif
64d6d1731bSAleksandr Iashchenko };
65d6d1731bSAleksandr Iashchenko 
664cafd8a3SAleksandr Iashchenko #ifdef __KERNEL__
6760aa5df7SAleksandr Iashchenko static struct asan_global_info __asan_global_info;
684cafd8a3SAleksandr Iashchenko #endif
6960aa5df7SAleksandr Iashchenko 
70d6d1731bSAleksandr Iashchenko static bool asan_active;
71d6d1731bSAleksandr Iashchenko static asan_panic_cb_t asan_panic_cb = asan_panic;
72d6d1731bSAleksandr Iashchenko 
asan_panic(void)734cafd8a3SAleksandr Iashchenko void __noreturn asan_panic(void)
744cafd8a3SAleksandr Iashchenko {
754cafd8a3SAleksandr Iashchenko #if defined(__KERNEL__)
764cafd8a3SAleksandr Iashchenko 	panic();
774cafd8a3SAleksandr Iashchenko #elif defined(__LDELF__)
784cafd8a3SAleksandr Iashchenko 	_ldelf_panic(2);
794cafd8a3SAleksandr Iashchenko #else
809f2dc7a1SAleksandr Iashchenko 	_utee_panic(TEE_ERROR_GENERIC);
814cafd8a3SAleksandr Iashchenko #endif
824cafd8a3SAleksandr Iashchenko 	/*
839f2dc7a1SAleksandr Iashchenko 	 * _utee_panic is not marked as noreturn.
844cafd8a3SAleksandr Iashchenko 	 * See _utee_panic prototype in utee_syscalls.h for reasoning. To
854cafd8a3SAleksandr Iashchenko 	 * prevent "‘noreturn’ function does return" warning the while loop
864cafd8a3SAleksandr Iashchenko 	 * is used.
874cafd8a3SAleksandr Iashchenko 	 */
884cafd8a3SAleksandr Iashchenko 	while (1)
894cafd8a3SAleksandr Iashchenko 		;
904cafd8a3SAleksandr Iashchenko }
914cafd8a3SAleksandr Iashchenko 
addr_crosses_scale_boundary(vaddr_t addr,size_t size)92d6d1731bSAleksandr Iashchenko static bool addr_crosses_scale_boundary(vaddr_t addr, size_t size)
93d6d1731bSAleksandr Iashchenko {
94d6d1731bSAleksandr Iashchenko 	return (addr >> ASAN_BLOCK_SHIFT) !=
95d6d1731bSAleksandr Iashchenko 	       ((addr + size - 1) >> ASAN_BLOCK_SHIFT);
96d6d1731bSAleksandr Iashchenko }
97d6d1731bSAleksandr Iashchenko 
va_to_shadow(const void * va)98d6d1731bSAleksandr Iashchenko static int8_t *va_to_shadow(const void *va)
99d6d1731bSAleksandr Iashchenko {
1004cafd8a3SAleksandr Iashchenko #if defined(__KERNEL__)
1014cafd8a3SAleksandr Iashchenko 	vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) +
1024cafd8a3SAleksandr Iashchenko 		     CFG_ASAN_SHADOW_OFFSET;
1034cafd8a3SAleksandr Iashchenko #else
1044cafd8a3SAleksandr Iashchenko 	vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) +
1054cafd8a3SAleksandr Iashchenko 		     CFG_USER_ASAN_SHADOW_OFFSET;
1064cafd8a3SAleksandr Iashchenko #endif
107d6d1731bSAleksandr Iashchenko 	return (int8_t *)sa;
108d6d1731bSAleksandr Iashchenko }
109d6d1731bSAleksandr Iashchenko 
va_range_to_shadow_size(const void * begin,const void * end)110d6d1731bSAleksandr Iashchenko static size_t va_range_to_shadow_size(const void *begin, const void *end)
111d6d1731bSAleksandr Iashchenko {
112d6d1731bSAleksandr Iashchenko 	return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE;
113d6d1731bSAleksandr Iashchenko }
114d6d1731bSAleksandr Iashchenko 
va_range_inside_shadow(const void * begin,const void * end)115d6d1731bSAleksandr Iashchenko static bool va_range_inside_shadow(const void *begin, const void *end)
116d6d1731bSAleksandr Iashchenko {
11760aa5df7SAleksandr Iashchenko 	struct asan_va_reg *regs = GET_ASAN_INFO()->regs;
118d6d1731bSAleksandr Iashchenko 	vaddr_t b = (vaddr_t)begin;
119d6d1731bSAleksandr Iashchenko 	vaddr_t e = (vaddr_t)end;
12060aa5df7SAleksandr Iashchenko 	unsigned int i = 0;
121d6d1731bSAleksandr Iashchenko 
122d6d1731bSAleksandr Iashchenko 	if (b >= e)
123d6d1731bSAleksandr Iashchenko 		return false;
12460aa5df7SAleksandr Iashchenko 
12560aa5df7SAleksandr Iashchenko 	for (i = 0; i < GET_ASAN_INFO()->regs_count; i++) {
12660aa5df7SAleksandr Iashchenko 		if (b >= regs[i].lo && e <= regs[i].hi) {
12760aa5df7SAleksandr Iashchenko 			/* Access is covered fully by at least one region */
12860aa5df7SAleksandr Iashchenko 			return true;
12960aa5df7SAleksandr Iashchenko 		}
13060aa5df7SAleksandr Iashchenko 	}
13160aa5df7SAleksandr Iashchenko 
13260aa5df7SAleksandr Iashchenko 	return false;
133d6d1731bSAleksandr Iashchenko }
134d6d1731bSAleksandr Iashchenko 
va_range_outside_shadow(const void * begin,const void * end)135d6d1731bSAleksandr Iashchenko static bool va_range_outside_shadow(const void *begin, const void *end)
136d6d1731bSAleksandr Iashchenko {
13760aa5df7SAleksandr Iashchenko 	struct asan_va_reg *regs = GET_ASAN_INFO()->regs;
138d6d1731bSAleksandr Iashchenko 	vaddr_t b = (vaddr_t)begin;
139d6d1731bSAleksandr Iashchenko 	vaddr_t e = (vaddr_t)end;
14060aa5df7SAleksandr Iashchenko 	unsigned int i = 0;
141d6d1731bSAleksandr Iashchenko 
142d6d1731bSAleksandr Iashchenko 	if (b >= e)
143d6d1731bSAleksandr Iashchenko 		return false;
14460aa5df7SAleksandr Iashchenko 
14560aa5df7SAleksandr Iashchenko 	for (i = 0; i < GET_ASAN_INFO()->regs_count; i++) {
14660aa5df7SAleksandr Iashchenko 		if (b < regs[i].hi && e > regs[i].lo) {
14760aa5df7SAleksandr Iashchenko 			/* Access covers region at least partly */
14860aa5df7SAleksandr Iashchenko 			return false;
14960aa5df7SAleksandr Iashchenko 		}
15060aa5df7SAleksandr Iashchenko 	}
15160aa5df7SAleksandr Iashchenko 
15260aa5df7SAleksandr Iashchenko 	return true;
153d6d1731bSAleksandr Iashchenko }
154d6d1731bSAleksandr Iashchenko 
va_misalignment(const void * va)155d6d1731bSAleksandr Iashchenko static size_t va_misalignment(const void *va)
156d6d1731bSAleksandr Iashchenko {
157d6d1731bSAleksandr Iashchenko 	return (vaddr_t)va & ASAN_BLOCK_MASK;
158d6d1731bSAleksandr Iashchenko }
159d6d1731bSAleksandr Iashchenko 
va_is_well_aligned(const void * va)160d6d1731bSAleksandr Iashchenko static bool va_is_well_aligned(const void *va)
161d6d1731bSAleksandr Iashchenko {
162d6d1731bSAleksandr Iashchenko 	return !va_misalignment(va);
163d6d1731bSAleksandr Iashchenko }
164d6d1731bSAleksandr Iashchenko 
asan_add_shadowed(const void * begin,const void * end,enum asan_va_reg_type type)165*b8a0c52cSAleksandr Iashchenko void asan_add_shadowed(const void *begin, const void *end,
166*b8a0c52cSAleksandr Iashchenko 		       enum asan_va_reg_type type)
167d6d1731bSAleksandr Iashchenko {
16860aa5df7SAleksandr Iashchenko 	struct asan_global_info *asan_info = GET_ASAN_INFO();
169*b8a0c52cSAleksandr Iashchenko 	struct asan_va_reg reg = {
170*b8a0c52cSAleksandr Iashchenko 		.lo = (vaddr_t)begin,
171*b8a0c52cSAleksandr Iashchenko 		.hi = (vaddr_t)end,
172*b8a0c52cSAleksandr Iashchenko 	};
173*b8a0c52cSAleksandr Iashchenko 	size_t idx = 0;
174d6d1731bSAleksandr Iashchenko 
175d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
176d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
17760aa5df7SAleksandr Iashchenko 	assert(reg.lo < reg.hi);
17860aa5df7SAleksandr Iashchenko 	if (asan_info->regs_count < ASAN_VA_REGS_MAX) {
179*b8a0c52cSAleksandr Iashchenko 		idx = asan_info->regs_count++;
180*b8a0c52cSAleksandr Iashchenko 		asan_info->regs[idx] = reg;
181*b8a0c52cSAleksandr Iashchenko 		asan_info->type[idx] = type;
18260aa5df7SAleksandr Iashchenko 	} else {
18360aa5df7SAleksandr Iashchenko 		EMSG("No free regions to allocate");
18460aa5df7SAleksandr Iashchenko 		asan_panic();
18560aa5df7SAleksandr Iashchenko 	}
186d6d1731bSAleksandr Iashchenko }
187d6d1731bSAleksandr Iashchenko 
asan_tag_no_access(const void * begin,const void * end)188d6d1731bSAleksandr Iashchenko void asan_tag_no_access(const void *begin, const void *end)
189d6d1731bSAleksandr Iashchenko {
190d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
191d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
192d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
193d6d1731bSAleksandr Iashchenko 
194d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), ASAN_DATA_RED_ZONE,
195d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
196d6d1731bSAleksandr Iashchenko }
197d6d1731bSAleksandr Iashchenko 
asan_tag_access(const void * begin,const void * end)198d6d1731bSAleksandr Iashchenko void asan_tag_access(const void *begin, const void *end)
199d6d1731bSAleksandr Iashchenko {
20060aa5df7SAleksandr Iashchenko 	if (!GET_ASAN_INFO()->regs_count || begin == end)
201d6d1731bSAleksandr Iashchenko 		return;
202d6d1731bSAleksandr Iashchenko 
203d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
204d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
205d6d1731bSAleksandr Iashchenko 
206d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), 0,
207d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
208d6d1731bSAleksandr Iashchenko 	if (!va_is_well_aligned(end))
209d6d1731bSAleksandr Iashchenko 		*va_to_shadow(end) = va_misalignment(end);
210d6d1731bSAleksandr Iashchenko }
211d6d1731bSAleksandr Iashchenko 
mpool_exists_in_range(vaddr_t begin,vaddr_t end)212*b8a0c52cSAleksandr Iashchenko static bool mpool_exists_in_range(vaddr_t begin, vaddr_t end)
213*b8a0c52cSAleksandr Iashchenko {
214*b8a0c52cSAleksandr Iashchenko 	struct asan_global_info *asan_info = GET_ASAN_INFO();
215*b8a0c52cSAleksandr Iashchenko 	struct asan_va_reg *regs = asan_info->regs;
216*b8a0c52cSAleksandr Iashchenko 	unsigned int i = 0;
217*b8a0c52cSAleksandr Iashchenko 
218*b8a0c52cSAleksandr Iashchenko 	for (i = 0; i < asan_info->regs_count; i++) {
219*b8a0c52cSAleksandr Iashchenko 		if (asan_info->type[i] == ASAN_REG_MEM_POOL &&
220*b8a0c52cSAleksandr Iashchenko 		    regs[i].hi <= end && regs[i].lo >= begin)
221*b8a0c52cSAleksandr Iashchenko 			return true;
222*b8a0c52cSAleksandr Iashchenko 	}
223*b8a0c52cSAleksandr Iashchenko 
224*b8a0c52cSAleksandr Iashchenko 	return false;
225*b8a0c52cSAleksandr Iashchenko }
226*b8a0c52cSAleksandr Iashchenko 
asan_tag_heap_free(const void * begin,const void * end)227d6d1731bSAleksandr Iashchenko void asan_tag_heap_free(const void *begin, const void *end)
228d6d1731bSAleksandr Iashchenko {
22960aa5df7SAleksandr Iashchenko 	if (!GET_ASAN_INFO()->regs_count)
230d6d1731bSAleksandr Iashchenko 		return;
231d6d1731bSAleksandr Iashchenko 
232d6d1731bSAleksandr Iashchenko 	assert(va_range_inside_shadow(begin, end));
233d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(begin));
234d6d1731bSAleksandr Iashchenko 	assert(va_is_well_aligned(end));
235d6d1731bSAleksandr Iashchenko 
236d6d1731bSAleksandr Iashchenko 	asan_memset_unchecked(va_to_shadow(begin), ASAN_HEAP_RED_ZONE,
237d6d1731bSAleksandr Iashchenko 			      va_range_to_shadow_size(begin, end));
238d6d1731bSAleksandr Iashchenko }
239d6d1731bSAleksandr Iashchenko 
asan_memset_unchecked(void * s,int c,size_t n)240d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall void *asan_memset_unchecked(void *s, int c, size_t n)
241d6d1731bSAleksandr Iashchenko {
242d6d1731bSAleksandr Iashchenko 	uint8_t *b = s;
243d6d1731bSAleksandr Iashchenko 	size_t m;
244d6d1731bSAleksandr Iashchenko 
245d6d1731bSAleksandr Iashchenko 	for (m = 0; m < n; m++)
246d6d1731bSAleksandr Iashchenko 		b[m] = c;
247d6d1731bSAleksandr Iashchenko 
248d6d1731bSAleksandr Iashchenko 	return s;
249d6d1731bSAleksandr Iashchenko }
250d6d1731bSAleksandr Iashchenko 
251d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall
asan_memcpy_unchecked(void * __restrict dst,const void * __restrict src,size_t len)252d6d1731bSAleksandr Iashchenko void *asan_memcpy_unchecked(void *__restrict dst, const void *__restrict src,
253d6d1731bSAleksandr Iashchenko 			    size_t len)
254d6d1731bSAleksandr Iashchenko {
255d6d1731bSAleksandr Iashchenko 	uint8_t *__restrict d = dst;
256d6d1731bSAleksandr Iashchenko 	const uint8_t *__restrict s = src;
257d6d1731bSAleksandr Iashchenko 	size_t n;
258d6d1731bSAleksandr Iashchenko 
259d6d1731bSAleksandr Iashchenko 	for (n = 0; n < len; n++)
260d6d1731bSAleksandr Iashchenko 		d[n] = s[n];
261d6d1731bSAleksandr Iashchenko 
262d6d1731bSAleksandr Iashchenko 	return dst;
263d6d1731bSAleksandr Iashchenko }
264d6d1731bSAleksandr Iashchenko 
asan_start(void)265d6d1731bSAleksandr Iashchenko void asan_start(void)
266d6d1731bSAleksandr Iashchenko {
26760aa5df7SAleksandr Iashchenko 	assert(GET_ASAN_INFO()->regs_count > 0 && !asan_active);
268d6d1731bSAleksandr Iashchenko 	asan_active = true;
269d6d1731bSAleksandr Iashchenko }
270d6d1731bSAleksandr Iashchenko 
asan_set_panic_cb(asan_panic_cb_t panic_cb)271d6d1731bSAleksandr Iashchenko void asan_set_panic_cb(asan_panic_cb_t panic_cb)
272d6d1731bSAleksandr Iashchenko {
273d6d1731bSAleksandr Iashchenko 	asan_panic_cb = panic_cb;
274d6d1731bSAleksandr Iashchenko }
275d6d1731bSAleksandr Iashchenko 
asan_report(vaddr_t addr,size_t size)276d6d1731bSAleksandr Iashchenko static void asan_report(vaddr_t addr, size_t size)
277d6d1731bSAleksandr Iashchenko {
278d6d1731bSAleksandr Iashchenko #ifdef KASAN_DUMP_SHADOW
279d6d1731bSAleksandr Iashchenko 	char buf[128] = {0};
280d6d1731bSAleksandr Iashchenko 	int r = 0, rc = 0;
281d6d1731bSAleksandr Iashchenko 	vaddr_t b = 0, e = 0, saddr = 0;
282d6d1731bSAleksandr Iashchenko 
283081fba0cSAleksandr Iashchenko 	b = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) - ASAN_BLOCK_SIZE * 2;
284081fba0cSAleksandr Iashchenko 	e = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) + ASAN_BLOCK_SIZE * 2;
285d6d1731bSAleksandr Iashchenko 
286d6d1731bSAleksandr Iashchenko 	/* Print shadow map nearby */
287d6d1731bSAleksandr Iashchenko 	if (va_range_inside_shadow((void *)b, (void *)e)) {
288d6d1731bSAleksandr Iashchenko 		rc = snprintk(buf + r, sizeof(buf) - r, "%lx: ", b);
289d6d1731bSAleksandr Iashchenko 		assert(rc > 0);
290d6d1731bSAleksandr Iashchenko 		r += rc;
291d6d1731bSAleksandr Iashchenko 		for (saddr = b; saddr <= e; saddr += ASAN_BLOCK_SIZE) {
292d6d1731bSAleksandr Iashchenko 			int8_t *sbyte = va_to_shadow((void *)saddr);
293d6d1731bSAleksandr Iashchenko 
294d6d1731bSAleksandr Iashchenko 			rc = snprintk(buf + r, sizeof(buf) - r,
295d6d1731bSAleksandr Iashchenko 				      "0x%02x ", (uint8_t)*sbyte);
296d6d1731bSAleksandr Iashchenko 			assert(rc > 0);
297d6d1731bSAleksandr Iashchenko 			r += rc;
298d6d1731bSAleksandr Iashchenko 		}
299d6d1731bSAleksandr Iashchenko 		EMSG("%s", buf);
300d6d1731bSAleksandr Iashchenko 	}
301d6d1731bSAleksandr Iashchenko #endif
302081fba0cSAleksandr Iashchenko 	EMSG("[ASAN]: access violation, addr: %#"PRIxVA" size: %zu",
303d6d1731bSAleksandr Iashchenko 	      addr, size);
304d6d1731bSAleksandr Iashchenko 
305d6d1731bSAleksandr Iashchenko 	asan_panic_cb();
306d6d1731bSAleksandr Iashchenko }
307d6d1731bSAleksandr Iashchenko 
asan_shadow_1byte_isvalid(vaddr_t addr)308d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_1byte_isvalid(vaddr_t addr)
309d6d1731bSAleksandr Iashchenko {
310d6d1731bSAleksandr Iashchenko 	int8_t last = (addr & ASAN_BLOCK_MASK) + 1;
311d6d1731bSAleksandr Iashchenko 	int8_t *byte = va_to_shadow((void *)addr);
312d6d1731bSAleksandr Iashchenko 
313d6d1731bSAleksandr Iashchenko 	if (*byte == 0 || last <= *byte)
314d6d1731bSAleksandr Iashchenko 		return true;
315d6d1731bSAleksandr Iashchenko 
316d6d1731bSAleksandr Iashchenko 	return false;
317d6d1731bSAleksandr Iashchenko }
318d6d1731bSAleksandr Iashchenko 
asan_shadow_2byte_isvalid(vaddr_t addr)319d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_2byte_isvalid(vaddr_t addr)
320d6d1731bSAleksandr Iashchenko {
321d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 2)) {
322d6d1731bSAleksandr Iashchenko 		return (asan_shadow_1byte_isvalid(addr) &&
323d6d1731bSAleksandr Iashchenko 			asan_shadow_1byte_isvalid(addr + 1));
324d6d1731bSAleksandr Iashchenko 	} else {
325d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 1) & ASAN_BLOCK_MASK) + 1;
326d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
327d6d1731bSAleksandr Iashchenko 
328d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
329d6d1731bSAleksandr Iashchenko 			return true;
330d6d1731bSAleksandr Iashchenko 
331d6d1731bSAleksandr Iashchenko 		return false;
332d6d1731bSAleksandr Iashchenko 	}
333d6d1731bSAleksandr Iashchenko }
334d6d1731bSAleksandr Iashchenko 
asan_shadow_4byte_isvalid(vaddr_t addr)335d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_4byte_isvalid(vaddr_t addr)
336d6d1731bSAleksandr Iashchenko {
337d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 4)) {
338d6d1731bSAleksandr Iashchenko 		return (asan_shadow_2byte_isvalid(addr) &&
339d6d1731bSAleksandr Iashchenko 			asan_shadow_2byte_isvalid(addr + 2));
340d6d1731bSAleksandr Iashchenko 	} else {
341d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 3) & ASAN_BLOCK_MASK) + 1;
342d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
343d6d1731bSAleksandr Iashchenko 
344d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
345d6d1731bSAleksandr Iashchenko 			return true;
346d6d1731bSAleksandr Iashchenko 
347d6d1731bSAleksandr Iashchenko 		return false;
348d6d1731bSAleksandr Iashchenko 	}
349d6d1731bSAleksandr Iashchenko }
350d6d1731bSAleksandr Iashchenko 
asan_shadow_8byte_isvalid(vaddr_t addr)351d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_8byte_isvalid(vaddr_t addr)
352d6d1731bSAleksandr Iashchenko {
353d6d1731bSAleksandr Iashchenko 	if (addr_crosses_scale_boundary(addr, 8)) {
354d6d1731bSAleksandr Iashchenko 		return (asan_shadow_4byte_isvalid(addr) &&
355d6d1731bSAleksandr Iashchenko 			asan_shadow_4byte_isvalid(addr + 4));
356d6d1731bSAleksandr Iashchenko 	} else {
357d6d1731bSAleksandr Iashchenko 		int8_t last = ((addr + 7) & ASAN_BLOCK_MASK) + 1;
358d6d1731bSAleksandr Iashchenko 		int8_t *byte = va_to_shadow((void *)addr);
359d6d1731bSAleksandr Iashchenko 
360d6d1731bSAleksandr Iashchenko 		if (*byte == 0 || last <= *byte)
361d6d1731bSAleksandr Iashchenko 			return true;
362d6d1731bSAleksandr Iashchenko 
363d6d1731bSAleksandr Iashchenko 		return false;
364d6d1731bSAleksandr Iashchenko 	}
365d6d1731bSAleksandr Iashchenko }
366d6d1731bSAleksandr Iashchenko 
asan_shadow_Nbyte_isvalid(vaddr_t addr,size_t size)367d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_Nbyte_isvalid(vaddr_t addr,
368d6d1731bSAleksandr Iashchenko 						      size_t size)
369d6d1731bSAleksandr Iashchenko {
370d6d1731bSAleksandr Iashchenko 	size_t i = 0;
371d6d1731bSAleksandr Iashchenko 
372d6d1731bSAleksandr Iashchenko 	for (; i < size; i++) {
373d6d1731bSAleksandr Iashchenko 		if (!asan_shadow_1byte_isvalid(addr + i))
374d6d1731bSAleksandr Iashchenko 			return false;
375d6d1731bSAleksandr Iashchenko 	}
376d6d1731bSAleksandr Iashchenko 
377d6d1731bSAleksandr Iashchenko 	return true;
378d6d1731bSAleksandr Iashchenko }
379d6d1731bSAleksandr Iashchenko 
check_access(vaddr_t addr,size_t size)380d6d1731bSAleksandr Iashchenko static __always_inline void check_access(vaddr_t addr, size_t size)
381d6d1731bSAleksandr Iashchenko {
382d6d1731bSAleksandr Iashchenko 	bool valid = false;
383d6d1731bSAleksandr Iashchenko 	void *begin = (void *)addr;
384d6d1731bSAleksandr Iashchenko 	void *end = (void *)(addr + size);
385d6d1731bSAleksandr Iashchenko 
386d6d1731bSAleksandr Iashchenko 	if (!asan_active)
387d6d1731bSAleksandr Iashchenko 		return;
388d6d1731bSAleksandr Iashchenko 	if (size == 0)
389d6d1731bSAleksandr Iashchenko 		return;
390d6d1731bSAleksandr Iashchenko 	if (va_range_outside_shadow(begin, end))
391d6d1731bSAleksandr Iashchenko 		return;
392d6d1731bSAleksandr Iashchenko 	/*
393d6d1731bSAleksandr Iashchenko 	 * If it isn't outside it has to be completely inside or there's a
394d6d1731bSAleksandr Iashchenko 	 * problem.
395d6d1731bSAleksandr Iashchenko 	 */
396d6d1731bSAleksandr Iashchenko 	if (!va_range_inside_shadow(begin, end))
3974cafd8a3SAleksandr Iashchenko 		asan_panic();
398d6d1731bSAleksandr Iashchenko 
399d6d1731bSAleksandr Iashchenko 	if (__builtin_constant_p(size)) {
400d6d1731bSAleksandr Iashchenko 		switch (size) {
401d6d1731bSAleksandr Iashchenko 		case 1:
402d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_1byte_isvalid(addr);
403d6d1731bSAleksandr Iashchenko 			break;
404d6d1731bSAleksandr Iashchenko 		case 2:
405d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_2byte_isvalid(addr);
406d6d1731bSAleksandr Iashchenko 			break;
407d6d1731bSAleksandr Iashchenko 		case 4:
408d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_4byte_isvalid(addr);
409d6d1731bSAleksandr Iashchenko 			break;
410d6d1731bSAleksandr Iashchenko 		case 8:
411d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_8byte_isvalid(addr);
412d6d1731bSAleksandr Iashchenko 			break;
413d6d1731bSAleksandr Iashchenko 		default:
414d6d1731bSAleksandr Iashchenko 			valid = asan_shadow_Nbyte_isvalid(addr, size);
415d6d1731bSAleksandr Iashchenko 			break;
416d6d1731bSAleksandr Iashchenko 		}
417d6d1731bSAleksandr Iashchenko 	} else {
418d6d1731bSAleksandr Iashchenko 		valid = asan_shadow_Nbyte_isvalid(addr, size);
419d6d1731bSAleksandr Iashchenko 	}
420d6d1731bSAleksandr Iashchenko 
421d6d1731bSAleksandr Iashchenko 	if (!valid)
422d6d1731bSAleksandr Iashchenko 		asan_report(addr, size);
423d6d1731bSAleksandr Iashchenko }
424d6d1731bSAleksandr Iashchenko 
check_load(vaddr_t addr,size_t size)425d6d1731bSAleksandr Iashchenko static __always_inline void check_load(vaddr_t addr, size_t size)
426d6d1731bSAleksandr Iashchenko {
427d6d1731bSAleksandr Iashchenko 	check_access(addr, size);
428d6d1731bSAleksandr Iashchenko }
429d6d1731bSAleksandr Iashchenko 
check_store(vaddr_t addr,size_t size)430d6d1731bSAleksandr Iashchenko static __always_inline void check_store(vaddr_t addr, size_t size)
431d6d1731bSAleksandr Iashchenko {
432d6d1731bSAleksandr Iashchenko 	check_access(addr, size);
433d6d1731bSAleksandr Iashchenko }
434d6d1731bSAleksandr Iashchenko 
report_load(vaddr_t addr __unused,size_t size __unused)435d6d1731bSAleksandr Iashchenko static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused)
436d6d1731bSAleksandr Iashchenko {
4374cafd8a3SAleksandr Iashchenko 	asan_panic();
438d6d1731bSAleksandr Iashchenko }
439d6d1731bSAleksandr Iashchenko 
report_store(vaddr_t addr __unused,size_t size __unused)440d6d1731bSAleksandr Iashchenko static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused)
441d6d1731bSAleksandr Iashchenko {
4424cafd8a3SAleksandr Iashchenko 	asan_panic();
443d6d1731bSAleksandr Iashchenko }
444d6d1731bSAleksandr Iashchenko 
445d6d1731bSAleksandr Iashchenko 
446d6d1731bSAleksandr Iashchenko 
447d6d1731bSAleksandr Iashchenko #define DEFINE_ASAN_FUNC(type, size)				\
448d6d1731bSAleksandr Iashchenko 	void __asan_##type##size(vaddr_t addr);			\
449d6d1731bSAleksandr Iashchenko 	void __asan_##type##size(vaddr_t addr)			\
450d6d1731bSAleksandr Iashchenko 	{ check_##type(addr, size); }				\
451d6d1731bSAleksandr Iashchenko 	void __asan_##type##size##_noabort(vaddr_t addr);	\
452d6d1731bSAleksandr Iashchenko 	void __asan_##type##size##_noabort(vaddr_t addr)	\
453d6d1731bSAleksandr Iashchenko 	{ check_##type(addr, size); }				\
454d6d1731bSAleksandr Iashchenko 	void __asan_report_##type##size##_noabort(vaddr_t addr);\
455d6d1731bSAleksandr Iashchenko 	void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \
456d6d1731bSAleksandr Iashchenko 	{ report_##type(addr, size); }
457d6d1731bSAleksandr Iashchenko 
458d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 1)
459d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 2)
460d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 4)
461d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 8)
462d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 16)
463d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 1)
464d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 2)
465d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 4)
466d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 8)
467d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 16)
468d6d1731bSAleksandr Iashchenko 
469d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size);
__asan_loadN_noabort(vaddr_t addr,size_t size)470d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size)
471d6d1731bSAleksandr Iashchenko {
472d6d1731bSAleksandr Iashchenko 	check_load(addr, size);
473d6d1731bSAleksandr Iashchenko }
474d6d1731bSAleksandr Iashchenko 
475d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size);
__asan_storeN_noabort(vaddr_t addr,size_t size)476d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size)
477d6d1731bSAleksandr Iashchenko {
478d6d1731bSAleksandr Iashchenko 	check_store(addr, size);
479d6d1731bSAleksandr Iashchenko }
480d6d1731bSAleksandr Iashchenko 
481d6d1731bSAleksandr Iashchenko void __asan_report_load_n_noabort(vaddr_t addr, size_t size);
__asan_report_load_n_noabort(vaddr_t addr,size_t size)482d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size)
483d6d1731bSAleksandr Iashchenko {
484d6d1731bSAleksandr Iashchenko 	report_load(addr, size);
485d6d1731bSAleksandr Iashchenko }
486d6d1731bSAleksandr Iashchenko 
487d6d1731bSAleksandr Iashchenko void __asan_report_store_n_noabort(vaddr_t addr, size_t size);
__asan_report_store_n_noabort(vaddr_t addr,size_t size)488d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size)
489d6d1731bSAleksandr Iashchenko {
490d6d1731bSAleksandr Iashchenko 	report_store(addr, size);
491d6d1731bSAleksandr Iashchenko }
492d6d1731bSAleksandr Iashchenko 
493d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void);
__asan_handle_no_return(void)494d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void)
495d6d1731bSAleksandr Iashchenko {
496d6d1731bSAleksandr Iashchenko }
497d6d1731bSAleksandr Iashchenko 
498d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size);
__asan_register_globals(struct asan_global * globals,size_t size)499d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size)
500d6d1731bSAleksandr Iashchenko {
501d6d1731bSAleksandr Iashchenko 	size_t n = 0;
502d6d1731bSAleksandr Iashchenko 
503d6d1731bSAleksandr Iashchenko 	for (n = 0; n < size; n++) {
504d6d1731bSAleksandr Iashchenko 		vaddr_t begin = globals[n].beg;
505d6d1731bSAleksandr Iashchenko 		vaddr_t end = begin + globals[n].size;
506d6d1731bSAleksandr Iashchenko 		vaddr_t end_align = ROUNDUP(end, ASAN_BLOCK_SIZE);
507d6d1731bSAleksandr Iashchenko 		vaddr_t end_rz = begin + globals[n].size_with_redzone;
508d6d1731bSAleksandr Iashchenko 
509*b8a0c52cSAleksandr Iashchenko 		if (!mpool_exists_in_range(begin, end))
510d6d1731bSAleksandr Iashchenko 			asan_tag_access((void *)begin, (void *)end);
511d6d1731bSAleksandr Iashchenko 		asan_tag_no_access((void *)end_align, (void *)end_rz);
512d6d1731bSAleksandr Iashchenko 	}
513d6d1731bSAleksandr Iashchenko }
514d6d1731bSAleksandr Iashchenko DECLARE_KEEP_INIT(__asan_register_globals);
515d6d1731bSAleksandr Iashchenko 
516d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals, size_t size);
__asan_unregister_globals(struct asan_global * globals __unused,size_t size __unused)517d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals __unused,
518d6d1731bSAleksandr Iashchenko 			       size_t size __unused)
519d6d1731bSAleksandr Iashchenko {
520d6d1731bSAleksandr Iashchenko }
521d6d1731bSAleksandr Iashchenko 
asan_handle_longjmp(void * old_sp)522d6d1731bSAleksandr Iashchenko void asan_handle_longjmp(void *old_sp)
523d6d1731bSAleksandr Iashchenko {
524d6d1731bSAleksandr Iashchenko 	void *top = old_sp;
525d6d1731bSAleksandr Iashchenko 	void *bottom = (void *)ROUNDDOWN((vaddr_t)&top,
526d6d1731bSAleksandr Iashchenko 					 ASAN_BLOCK_SIZE);
527d6d1731bSAleksandr Iashchenko 
528d6d1731bSAleksandr Iashchenko 	asan_tag_access(bottom, top);
529d6d1731bSAleksandr Iashchenko }
5304cafd8a3SAleksandr Iashchenko 
5314cafd8a3SAleksandr Iashchenko #if !defined(__KERNEL__)
5324cafd8a3SAleksandr Iashchenko 
asan_map_shadow_region(vaddr_t lo,vaddr_t hi)5334cafd8a3SAleksandr Iashchenko static int asan_map_shadow_region(vaddr_t lo, vaddr_t hi)
5344cafd8a3SAleksandr Iashchenko {
5354cafd8a3SAleksandr Iashchenko 	struct asan_global_info *asan_info = GET_ASAN_INFO();
5364cafd8a3SAleksandr Iashchenko 	TEE_Result rc = TEE_SUCCESS;
5374cafd8a3SAleksandr Iashchenko 	size_t sz = hi - lo;
5384cafd8a3SAleksandr Iashchenko 	vaddr_t req = lo;
5394cafd8a3SAleksandr Iashchenko 
5404cafd8a3SAleksandr Iashchenko 	if (asan_info->s_regs_count >= ASAN_VA_REGS_MAX)
5414cafd8a3SAleksandr Iashchenko 		return -1;
5424cafd8a3SAleksandr Iashchenko 
5434cafd8a3SAleksandr Iashchenko #if defined(__LDELF__)
5444cafd8a3SAleksandr Iashchenko 	rc = _ldelf_map_zi(&req, sz, 0, 0, 0);
5454cafd8a3SAleksandr Iashchenko #else
5469f2dc7a1SAleksandr Iashchenko 	req = (vaddr_t)tee_map_zi_va(req, sz, 0);
5474cafd8a3SAleksandr Iashchenko #endif
5484cafd8a3SAleksandr Iashchenko 	if (rc != TEE_SUCCESS)
5494cafd8a3SAleksandr Iashchenko 		return -1;
5504cafd8a3SAleksandr Iashchenko 	if (req != lo)
5514cafd8a3SAleksandr Iashchenko 		return -1;
5524cafd8a3SAleksandr Iashchenko 
5534cafd8a3SAleksandr Iashchenko 	asan_info->s_regs[asan_info->s_regs_count++] =
5544cafd8a3SAleksandr Iashchenko 		(struct asan_va_reg){ lo, hi };
5554cafd8a3SAleksandr Iashchenko 
5564cafd8a3SAleksandr Iashchenko 	return 0;
5574cafd8a3SAleksandr Iashchenko }
5584cafd8a3SAleksandr Iashchenko 
asan_user_map_shadow(void * lo,void * hi,enum asan_va_reg_type type)559*b8a0c52cSAleksandr Iashchenko int asan_user_map_shadow(void *lo, void *hi, enum asan_va_reg_type type)
5604cafd8a3SAleksandr Iashchenko {
5614cafd8a3SAleksandr Iashchenko 	vaddr_t lo_s = 0;
5624cafd8a3SAleksandr Iashchenko 	vaddr_t hi_s = 0;
5634cafd8a3SAleksandr Iashchenko 	int rc = 0;
5644cafd8a3SAleksandr Iashchenko 
5654cafd8a3SAleksandr Iashchenko 	if (lo == hi)
5664cafd8a3SAleksandr Iashchenko 		return -1;
5674cafd8a3SAleksandr Iashchenko 
5684cafd8a3SAleksandr Iashchenko 	lo_s = ROUNDDOWN((vaddr_t)va_to_shadow(lo), SMALL_PAGE_SIZE);
5694cafd8a3SAleksandr Iashchenko 	hi_s = ROUNDUP((vaddr_t)va_to_shadow(hi), SMALL_PAGE_SIZE);
5704cafd8a3SAleksandr Iashchenko 
5714cafd8a3SAleksandr Iashchenko 	if (lo_s >= hi_s)
5724cafd8a3SAleksandr Iashchenko 		return -1;
5734cafd8a3SAleksandr Iashchenko 	if (hi >= (void *)GET_ASAN_INFO())
5744cafd8a3SAleksandr Iashchenko 		return -1;
5754cafd8a3SAleksandr Iashchenko 
5764cafd8a3SAleksandr Iashchenko 	/*
5774cafd8a3SAleksandr Iashchenko 	 * Walk the already mapped shadow ranges and trim [lo_s, hi_s)
5784cafd8a3SAleksandr Iashchenko 	 * down to the part that is still missing.
5794cafd8a3SAleksandr Iashchenko 	 */
5804cafd8a3SAleksandr Iashchenko 	for (size_t i = 0; i < GET_ASAN_INFO()->s_regs_count; i++) {
5814cafd8a3SAleksandr Iashchenko 		vaddr_t reg_lo_s = GET_ASAN_INFO()->s_regs[i].lo;
5824cafd8a3SAleksandr Iashchenko 		vaddr_t reg_hi_s = GET_ASAN_INFO()->s_regs[i].hi;
5834cafd8a3SAleksandr Iashchenko 
5844cafd8a3SAleksandr Iashchenko 		if (reg_hi_s <= lo_s || reg_lo_s >= hi_s) {
5854cafd8a3SAleksandr Iashchenko 			/*
5864cafd8a3SAleksandr Iashchenko 			 * This mapped range does not intersect the
5874cafd8a3SAleksandr Iashchenko 			 * requested range. Skip it.
5884cafd8a3SAleksandr Iashchenko 			 */
5894cafd8a3SAleksandr Iashchenko 			continue;
5904cafd8a3SAleksandr Iashchenko 		}
5914cafd8a3SAleksandr Iashchenko 		if (reg_lo_s <= lo_s && reg_hi_s >= hi_s) {
5924cafd8a3SAleksandr Iashchenko 			/*
5934cafd8a3SAleksandr Iashchenko 			 * The requested shadow range is already fully
5944cafd8a3SAleksandr Iashchenko 			 * mapped, so there is nothing left to do.
5954cafd8a3SAleksandr Iashchenko 			 */
5964cafd8a3SAleksandr Iashchenko 			goto out;
5974cafd8a3SAleksandr Iashchenko 		}
5984cafd8a3SAleksandr Iashchenko 		if (reg_lo_s <= lo_s && reg_hi_s < hi_s) {
5994cafd8a3SAleksandr Iashchenko 			/*
6004cafd8a3SAleksandr Iashchenko 			 * The mapped range covers the left side of
6014cafd8a3SAleksandr Iashchenko 			 * the requested range.
6024cafd8a3SAleksandr Iashchenko 			 */
6034cafd8a3SAleksandr Iashchenko 			lo_s = reg_hi_s;
6044cafd8a3SAleksandr Iashchenko 			continue;
6054cafd8a3SAleksandr Iashchenko 		}
6064cafd8a3SAleksandr Iashchenko 		if (reg_lo_s > lo_s && reg_hi_s >= hi_s) {
6074cafd8a3SAleksandr Iashchenko 			/*
6084cafd8a3SAleksandr Iashchenko 			 * The mapped range covers the right side of
6094cafd8a3SAleksandr Iashchenko 			 * the requested range.
6104cafd8a3SAleksandr Iashchenko 			 */
6114cafd8a3SAleksandr Iashchenko 			hi_s = reg_lo_s;
6124cafd8a3SAleksandr Iashchenko 			continue;
6134cafd8a3SAleksandr Iashchenko 		}
6144cafd8a3SAleksandr Iashchenko 		/*
6154cafd8a3SAleksandr Iashchenko 		 * If we are here then there is a problem, that shouldn't
6164cafd8a3SAleksandr Iashchenko 		 * happen for valid shadow mapping intervals.
6174cafd8a3SAleksandr Iashchenko 		 */
6184cafd8a3SAleksandr Iashchenko 		EMSG("can't handle: reg_lo_s %#"PRIxVA" reg_hi_s %#"
6194cafd8a3SAleksandr Iashchenko 		     PRIxVA" lo_s %#"PRIxVA" hi_s %#"PRIxVA, reg_lo_s,
6204cafd8a3SAleksandr Iashchenko 		     reg_hi_s, lo_s, hi_s);
6214cafd8a3SAleksandr Iashchenko 		asan_panic();
6224cafd8a3SAleksandr Iashchenko 	}
6234cafd8a3SAleksandr Iashchenko 	/*
6244cafd8a3SAleksandr Iashchenko 	 * If we reach this point, [lo_s, hi_s) is the remaining shadow
6254cafd8a3SAleksandr Iashchenko 	 * gap that still needs to be mapped.
6264cafd8a3SAleksandr Iashchenko 	 */
6274cafd8a3SAleksandr Iashchenko 	assert(hi_s > lo_s);
6284cafd8a3SAleksandr Iashchenko 	rc = asan_map_shadow_region(lo_s, hi_s);
6294cafd8a3SAleksandr Iashchenko 	if (rc) {
6304cafd8a3SAleksandr Iashchenko 		EMSG("Failed to map shadow region");
6314cafd8a3SAleksandr Iashchenko 		asan_panic();
6324cafd8a3SAleksandr Iashchenko 	}
6334cafd8a3SAleksandr Iashchenko out:
6344cafd8a3SAleksandr Iashchenko 	/* Remember the original VA range as checked by ASan. */
635*b8a0c52cSAleksandr Iashchenko 	asan_add_shadowed(lo, hi, type);
6364cafd8a3SAleksandr Iashchenko 	return 0;
6374cafd8a3SAleksandr Iashchenko }
6384cafd8a3SAleksandr Iashchenko 
6394cafd8a3SAleksandr Iashchenko #else
6404cafd8a3SAleksandr Iashchenko 
asan_user_map_shadow(void * lo __unused,void * hi __unused,enum asan_va_reg_type type __unused)641*b8a0c52cSAleksandr Iashchenko int asan_user_map_shadow(void *lo __unused, void *hi __unused,
642*b8a0c52cSAleksandr Iashchenko 			 enum asan_va_reg_type type __unused)
6434cafd8a3SAleksandr Iashchenko {
6444cafd8a3SAleksandr Iashchenko 	return 0;
6454cafd8a3SAleksandr Iashchenko }
6464cafd8a3SAleksandr Iashchenko #endif
647