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