xref: /optee_os/core/kernel/asan.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
21d171f95SJens Wiklander /*
31d171f95SJens Wiklander  * Copyright (c) 2016, Linaro Limited
41d171f95SJens Wiklander  * All rights reserved.
51d171f95SJens Wiklander  *
61d171f95SJens Wiklander  * Redistribution and use in source and binary forms, with or without
71d171f95SJens Wiklander  * modification, are permitted provided that the following conditions are met:
81d171f95SJens Wiklander  *
91d171f95SJens Wiklander  * 1. Redistributions of source code must retain the above copyright notice,
101d171f95SJens Wiklander  * this list of conditions and the following disclaimer.
111d171f95SJens Wiklander  *
121d171f95SJens Wiklander  * 2. Redistributions in binary form must reproduce the above copyright notice,
131d171f95SJens Wiklander  * this list of conditions and the following disclaimer in the documentation
141d171f95SJens Wiklander  * and/or other materials provided with the distribution.
151d171f95SJens Wiklander  *
161d171f95SJens Wiklander  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
171d171f95SJens Wiklander  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181d171f95SJens Wiklander  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191d171f95SJens Wiklander  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
201d171f95SJens Wiklander  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211d171f95SJens Wiklander  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221d171f95SJens Wiklander  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231d171f95SJens Wiklander  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241d171f95SJens Wiklander  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251d171f95SJens Wiklander  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261d171f95SJens Wiklander  * POSSIBILITY OF SUCH DAMAGE.
271d171f95SJens Wiklander  */
281d171f95SJens Wiklander 
291d171f95SJens Wiklander #include <assert.h>
301d171f95SJens Wiklander #include <compiler.h>
310b1d6bacSJens Wiklander #include <keep.h>
321d171f95SJens Wiklander #include <kernel/asan.h>
330b1d6bacSJens Wiklander #include <kernel/panic.h>
341d171f95SJens Wiklander #include <string.h>
350b1d6bacSJens Wiklander #include <trace.h>
361d171f95SJens Wiklander #include <types_ext.h>
371d171f95SJens Wiklander #include <util.h>
381d171f95SJens Wiklander 
391d171f95SJens Wiklander struct asan_source_location {
401d171f95SJens Wiklander 	const char *file_name;
411d171f95SJens Wiklander 	int line_no;
421d171f95SJens Wiklander 	int column_no;
431d171f95SJens Wiklander };
441d171f95SJens Wiklander 
451d171f95SJens Wiklander struct asan_global {
461d171f95SJens Wiklander 	uintptr_t beg;
471d171f95SJens Wiklander 	uintptr_t size;
481d171f95SJens Wiklander 	uintptr_t size_with_redzone;
491d171f95SJens Wiklander 	const char *name;
501d171f95SJens Wiklander 	const char *module_name;
511d171f95SJens Wiklander 	uintptr_t has_dynamic_init;
521d171f95SJens Wiklander 	struct asan_source_location *location;
531d171f95SJens Wiklander };
541d171f95SJens Wiklander 
551d171f95SJens Wiklander static vaddr_t asan_va_base;
561d171f95SJens Wiklander static size_t asan_va_size;
571d171f95SJens Wiklander static bool asan_active;
581d171f95SJens Wiklander 
59bce4951cSJens Wiklander static int8_t *va_to_shadow(const void *va)
601d171f95SJens Wiklander {
611d171f95SJens Wiklander 	vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET;
621d171f95SJens Wiklander 
631d171f95SJens Wiklander 	return (int8_t *)sa;
641d171f95SJens Wiklander }
651d171f95SJens Wiklander 
66bce4951cSJens Wiklander static size_t va_range_to_shadow_size(const void *begin, const void *end)
671d171f95SJens Wiklander {
681d171f95SJens Wiklander 	return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE;
691d171f95SJens Wiklander }
701d171f95SJens Wiklander 
71bce4951cSJens Wiklander static bool va_range_inside_shadow(const void *begin, const void *end)
721d171f95SJens Wiklander {
731d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
741d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
751d171f95SJens Wiklander 
761d171f95SJens Wiklander 	if (b >= e)
771d171f95SJens Wiklander 		return false;
781d171f95SJens Wiklander 	return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size));
791d171f95SJens Wiklander }
801d171f95SJens Wiklander 
81bce4951cSJens Wiklander static bool va_range_outside_shadow(const void *begin, const void *end)
821d171f95SJens Wiklander {
831d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
841d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
851d171f95SJens Wiklander 
861d171f95SJens Wiklander 	if (b >= e)
871d171f95SJens Wiklander 		return false;
881d171f95SJens Wiklander 	return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size));
891d171f95SJens Wiklander }
901d171f95SJens Wiklander 
91bce4951cSJens Wiklander static size_t va_misalignment(const void *va)
921d171f95SJens Wiklander {
931d171f95SJens Wiklander 	return (vaddr_t)va & ASAN_BLOCK_MASK;
941d171f95SJens Wiklander }
951d171f95SJens Wiklander 
96bce4951cSJens Wiklander static bool va_is_well_aligned(const void *va)
971d171f95SJens Wiklander {
981d171f95SJens Wiklander 	return !va_misalignment(va);
991d171f95SJens Wiklander }
1001d171f95SJens Wiklander 
101bce4951cSJens Wiklander void asan_set_shadowed(const void *begin, const void *end)
1021d171f95SJens Wiklander {
1031d171f95SJens Wiklander 	vaddr_t b = (vaddr_t)begin;
1041d171f95SJens Wiklander 	vaddr_t e = (vaddr_t)end;
1051d171f95SJens Wiklander 
1061d171f95SJens Wiklander 	assert(!asan_va_base);
1071d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
1081d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
1091d171f95SJens Wiklander 	assert(b < e);
1101d171f95SJens Wiklander 
1111d171f95SJens Wiklander 	asan_va_base = b;
1121d171f95SJens Wiklander 	asan_va_size = e - b;
1131d171f95SJens Wiklander }
1141d171f95SJens Wiklander 
115bce4951cSJens Wiklander void asan_tag_no_access(const void *begin, const void *end)
1161d171f95SJens Wiklander {
1171d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
1181d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
1191d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
1201d171f95SJens Wiklander 
121abccd909SJens Wiklander 	asan_memset_unchecked(va_to_shadow(begin), ASAN_DATA_RED_ZONE,
1221d171f95SJens Wiklander 			      va_range_to_shadow_size(begin, end));
1231d171f95SJens Wiklander }
1241d171f95SJens Wiklander 
125bce4951cSJens Wiklander void asan_tag_access(const void *begin, const void *end)
1261d171f95SJens Wiklander {
12724fe8015SJens Wiklander 	if (!asan_va_base || (begin == end))
1281d171f95SJens Wiklander 		return;
1291d171f95SJens Wiklander 
1301d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
1311d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
1321d171f95SJens Wiklander 
133abccd909SJens Wiklander 	asan_memset_unchecked(va_to_shadow(begin), 0,
134abccd909SJens Wiklander 			      va_range_to_shadow_size(begin, end));
1351d171f95SJens Wiklander 	if (!va_is_well_aligned(end))
1361d171f95SJens Wiklander 		*va_to_shadow(end) = ASAN_BLOCK_SIZE - va_misalignment(end);
1371d171f95SJens Wiklander }
1381d171f95SJens Wiklander 
139bce4951cSJens Wiklander void asan_tag_heap_free(const void *begin, const void *end)
1401d171f95SJens Wiklander {
1411d171f95SJens Wiklander 	if (!asan_va_base)
1421d171f95SJens Wiklander 		return;
1431d171f95SJens Wiklander 
1441d171f95SJens Wiklander 	assert(va_range_inside_shadow(begin, end));
1451d171f95SJens Wiklander 	assert(va_is_well_aligned(begin));
1461d171f95SJens Wiklander 	assert(va_is_well_aligned(end));
1471d171f95SJens Wiklander 
148abccd909SJens Wiklander 	asan_memset_unchecked(va_to_shadow(begin), ASAN_HEAP_RED_ZONE,
1491d171f95SJens Wiklander 			      va_range_to_shadow_size(begin, end));
1501d171f95SJens Wiklander }
1511d171f95SJens Wiklander 
152abccd909SJens Wiklander void *asan_memset_unchecked(void *s, int c, size_t n)
153abccd909SJens Wiklander {
154abccd909SJens Wiklander 	uint8_t *b = s;
155abccd909SJens Wiklander 	size_t m;
156abccd909SJens Wiklander 
157abccd909SJens Wiklander 	for (m = 0; m < n; m++)
158abccd909SJens Wiklander 		b[m] = c;
159abccd909SJens Wiklander 
160abccd909SJens Wiklander 	return s;
161abccd909SJens Wiklander }
162abccd909SJens Wiklander 
16306fe4216SJens Wiklander void *asan_memcpy_unchecked(void *__restrict dst, const void *__restrict src,
16406fe4216SJens Wiklander 			    size_t len)
16506fe4216SJens Wiklander {
16606fe4216SJens Wiklander 	uint8_t *__restrict d = dst;
16706fe4216SJens Wiklander 	const uint8_t *__restrict s = src;
16806fe4216SJens Wiklander 	size_t n;
16906fe4216SJens Wiklander 
17006fe4216SJens Wiklander 	for (n = 0; n < len; n++)
17106fe4216SJens Wiklander 		d[n] = s[n];
17206fe4216SJens Wiklander 
17306fe4216SJens Wiklander 	return dst;
17406fe4216SJens Wiklander }
17506fe4216SJens Wiklander 
1761d171f95SJens Wiklander void asan_start(void)
1771d171f95SJens Wiklander {
1781d171f95SJens Wiklander 	assert(asan_va_base && !asan_active);
1791d171f95SJens Wiklander 	asan_active = true;
1801d171f95SJens Wiklander }
1811d171f95SJens Wiklander 
1821d171f95SJens Wiklander static void check_access(vaddr_t addr, size_t size)
1831d171f95SJens Wiklander {
1841d171f95SJens Wiklander 	void *begin = (void *)addr;
1851d171f95SJens Wiklander 	void *end = (void *)(addr + size);
1861d171f95SJens Wiklander 	int8_t *a;
1871d171f95SJens Wiklander 	int8_t *e;
1881d171f95SJens Wiklander 
1891d171f95SJens Wiklander 	if (!asan_active || !size)
1901d171f95SJens Wiklander 		return;
1911d171f95SJens Wiklander 	if (va_range_outside_shadow(begin, end))
1921d171f95SJens Wiklander 		return;
1931d171f95SJens Wiklander 	/*
1941d171f95SJens Wiklander 	 * If it isn't outside it has to be completely inside or there's a
1951d171f95SJens Wiklander 	 * problem.
1961d171f95SJens Wiklander 	 */
1971d171f95SJens Wiklander 	if (!va_range_inside_shadow(begin, end))
1981d171f95SJens Wiklander 		panic();
1991d171f95SJens Wiklander 
200726ce13eSJens Wiklander 	e = va_to_shadow((void *)(addr + size - 1));
201726ce13eSJens Wiklander 	for (a = va_to_shadow(begin); a <= e; a++)
2021d171f95SJens Wiklander 		if (*a < 0)
2031d171f95SJens Wiklander 			panic();
2041d171f95SJens Wiklander 
2051d171f95SJens Wiklander 	if (!va_is_well_aligned(end) &&
2061d171f95SJens Wiklander 	    va_misalignment(end) > (size_t)(*e - ASAN_BLOCK_SIZE))
2071d171f95SJens Wiklander 		panic();
2081d171f95SJens Wiklander }
2091d171f95SJens Wiklander 
2101d171f95SJens Wiklander static void check_load(vaddr_t addr, size_t size)
2111d171f95SJens Wiklander {
2121d171f95SJens Wiklander 	check_access(addr, size);
2131d171f95SJens Wiklander }
2141d171f95SJens Wiklander 
2151d171f95SJens Wiklander static void check_store(vaddr_t addr, size_t size)
2161d171f95SJens Wiklander {
2171d171f95SJens Wiklander 	check_access(addr, size);
2181d171f95SJens Wiklander }
2191d171f95SJens Wiklander 
2201d171f95SJens Wiklander static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused)
2211d171f95SJens Wiklander {
2221d171f95SJens Wiklander 	panic();
2231d171f95SJens Wiklander }
2241d171f95SJens Wiklander 
2251d171f95SJens Wiklander static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused)
2261d171f95SJens Wiklander {
2271d171f95SJens Wiklander 	panic();
2281d171f95SJens Wiklander }
2291d171f95SJens Wiklander 
2301d171f95SJens Wiklander 
2311d171f95SJens Wiklander 
2321d171f95SJens Wiklander #define DEFINE_ASAN_FUNC(type, size)				\
2331d171f95SJens Wiklander 	void __asan_##type##size(vaddr_t addr);			\
2341d171f95SJens Wiklander 	void __asan_##type##size(vaddr_t addr)			\
2351d171f95SJens Wiklander 	{ check_##type(addr, size); }				\
2361d171f95SJens Wiklander 	void __asan_##type##size##_noabort(vaddr_t addr);	\
2371d171f95SJens Wiklander 	void __asan_##type##size##_noabort(vaddr_t addr)	\
2381d171f95SJens Wiklander 	{ check_##type(addr, size); }				\
2391d171f95SJens Wiklander 	void __asan_report_##type##size##_noabort(vaddr_t addr);\
2401d171f95SJens Wiklander 	void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \
2411d171f95SJens Wiklander 	{ report_##type(addr, size); }
2421d171f95SJens Wiklander 
2431d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 1)
2441d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 2)
2451d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 4)
2461d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 8)
2471d171f95SJens Wiklander DEFINE_ASAN_FUNC(load, 16)
2481d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 1)
2491d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 2)
2501d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 4)
2511d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 8)
2521d171f95SJens Wiklander DEFINE_ASAN_FUNC(store, 16)
2531d171f95SJens Wiklander 
2541d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size);
2551d171f95SJens Wiklander void __asan_loadN_noabort(vaddr_t addr, size_t size)
2561d171f95SJens Wiklander {
2571d171f95SJens Wiklander 	check_load(addr, size);
2581d171f95SJens Wiklander }
2591d171f95SJens Wiklander 
2601d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size);
2611d171f95SJens Wiklander void __asan_storeN_noabort(vaddr_t addr, size_t size)
2621d171f95SJens Wiklander {
2631d171f95SJens Wiklander 	check_store(addr, size);
2641d171f95SJens Wiklander }
2651d171f95SJens Wiklander 
2661d171f95SJens Wiklander void __asan_report_load_n_noabort(vaddr_t addr, size_t size);
2671d171f95SJens Wiklander void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size)
2681d171f95SJens Wiklander {
2691d171f95SJens Wiklander 	report_load(addr, size);
2701d171f95SJens Wiklander }
2711d171f95SJens Wiklander 
2721d171f95SJens Wiklander void __asan_report_store_n_noabort(vaddr_t addr, size_t size);
2731d171f95SJens Wiklander void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size)
2741d171f95SJens Wiklander {
2751d171f95SJens Wiklander 	report_store(addr, size);
2761d171f95SJens Wiklander }
2771d171f95SJens Wiklander 
2781d171f95SJens Wiklander void __asan_handle_no_return(void);
279ce553c81SJens Wiklander void __asan_handle_no_return(void)
2801d171f95SJens Wiklander {
2811d171f95SJens Wiklander }
2821d171f95SJens Wiklander 
2831d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size);
2841d171f95SJens Wiklander void __asan_register_globals(struct asan_global *globals, size_t size)
2851d171f95SJens Wiklander {
2861d171f95SJens Wiklander 	size_t n;
2871d171f95SJens Wiklander 
2881d171f95SJens Wiklander 	for (n = 0; n < size; n++)
2891d171f95SJens Wiklander 		asan_tag_access((void *)globals[n].beg,
2901d171f95SJens Wiklander 				(void *)(globals[n].beg + globals[n].size));
2911d171f95SJens Wiklander }
2920b1d6bacSJens Wiklander KEEP_INIT(__asan_register_globals);
2931d171f95SJens Wiklander 
2941d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals, size_t size);
2951d171f95SJens Wiklander void __asan_unregister_globals(struct asan_global *globals __unused,
2961d171f95SJens Wiklander 			       size_t size __unused)
2971d171f95SJens Wiklander {
2981d171f95SJens Wiklander }
299