From 6cd9d2d600f3764a4c51d1a735e36397d91334f3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 17 Sep 2020 09:39:17 +0200 Subject: Add KASan support KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides a fast and comprehensive solution for finding use-after-free and out-of-bounds bugs. This adds support for KASan to barebox. It is basically a stripped down version taken from the Linux Kernel as of v5.9-rc1. Quoting the initial Linux commit 0b24becc810d ("kasan: add kernel address sanitizer infrastructure") describes what KASan does: | KASAN uses compile-time instrumentation for checking every memory access, | therefore GCC > v4.9.2 required. v4.9.2 almost works, but has issues with | putting symbol aliases into the wrong section, which breaks kasan | instrumentation of globals. | | Basic idea: | | The main idea of KASAN is to use shadow memory to record whether each byte | of memory is safe to access or not, and use compiler's instrumentation to | check the shadow memory on each memory access. | | Address sanitizer uses 1/8 of the memory addressable in kernel for shadow | memory and uses direct mapping with a scale and offset to translate a | memory address to its corresponding shadow address. | | For every 8 bytes there is one corresponding byte of shadow memory. | The following encoding used for each shadow byte: 0 means that all 8 bytes | of the corresponding memory region are valid for access; k (1 <= k <= 7) | means that the first k bytes are valid for access, and other (8 - k) bytes | are not; Any negative value indicates that the entire 8-bytes are | inaccessible. Different negative values used to distinguish between | different kinds of inaccessible memory (redzones, freed memory) (see | mm/kasan/kasan.h). | | To be able to detect accesses to bad memory we need a special compiler. | Such compiler inserts a specific function calls (__asan_load*(addr), | __asan_store*(addr)) before each memory access of size 1, 2, 4, 8 or 16. | | These functions check whether memory region is valid to access or not by | checking corresponding shadow memory. If access is not valid an error | printed. Signed-off-by: Sascha Hauer --- include/linux/kasan.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 include/linux/kasan.h (limited to 'include/linux') diff --git a/include/linux/kasan.h b/include/linux/kasan.h new file mode 100644 index 0000000000..7c184cd0e2 --- /dev/null +++ b/include/linux/kasan.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KASAN_H +#define _LINUX_KASAN_H + +#include + +/* + * On 64bit architectures tlsf aligns all allocations to a 64bit + * boundary, otherwise they are only 32bit aligned. + */ +#ifdef CONFIG_64BIT +#define KASAN_SHADOW_SCALE_SHIFT 3 +#else +#define KASAN_SHADOW_SCALE_SHIFT 2 +#endif + +#define KASAN_TAG_KERNEL 0xFF /* native kernel pointers tag */ +#define KASAN_TAG_INVALID 0xFE /* inaccessible memory tag */ +#define KASAN_TAG_MAX 0xFD /* maximum value for random tags */ + +#define KASAN_FREE_PAGE 0xFF /* page was freed */ +#define KASAN_PAGE_REDZONE 0xFE /* redzone for kmalloc_large allocations */ +#define KASAN_KMALLOC_REDZONE 0xFC /* redzone inside slub object */ +#define KASAN_KMALLOC_FREE 0xFB /* object was freed (kmem_cache_free/kfree) */ +#define KASAN_KMALLOC_FREETRACK 0xFA /* object was freed and has free track set */ + +#define KASAN_GLOBAL_REDZONE 0xF9 /* redzone for global variable */ +#define KASAN_VMALLOC_INVALID 0xF8 /* unallocated space in vmapped page */ + +/* + * Stack redzone shadow values + * (Those are compiler's ABI, don't change them) + */ +#define KASAN_STACK_LEFT 0xF1 +#define KASAN_STACK_MID 0xF2 +#define KASAN_STACK_RIGHT 0xF3 +#define KASAN_STACK_PARTIAL 0xF4 + +/* + * alloca redzone shadow values + */ +#define KASAN_ALLOCA_LEFT 0xCA +#define KASAN_ALLOCA_RIGHT 0xCB + +#ifdef CONFIG_KASAN + +extern unsigned long kasan_shadow_start; +extern unsigned long kasan_shadow_base; + +static inline void *kasan_mem_to_shadow(const void *addr) +{ + unsigned long a = (unsigned long)addr; + + a -= kasan_shadow_start; + a >>= KASAN_SHADOW_SCALE_SHIFT; + a += kasan_shadow_base; + + return (void *)a; +} + +void kasan_init(unsigned long membase, unsigned long memsize, + unsigned long shadow_base); + +/* Enable reporting bugs after kasan_disable_current() */ +extern void kasan_enable_current(void); + +/* Disable reporting bugs for current task */ +extern void kasan_disable_current(void); + +void kasan_poison_shadow(const void *address, size_t size, u8 value); +void kasan_unpoison_shadow(const void *address, size_t size); + +bool kasan_save_enable_multi_shot(void); +void kasan_restore_multi_shot(bool enabled); + +#else /* CONFIG_KASAN */ + +static inline void kasan_poison_shadow(const void *address, size_t size, u8 value) {} +static inline void kasan_unpoison_shadow(const void *address, size_t size) {} + +static inline void kasan_enable_current(void) {} +static inline void kasan_disable_current(void) {} + +static inline void kasan_init(unsigned long membase, unsigned long memsize, + unsigned long shadow_base) {} + +#endif /* CONFIG_KASAN */ + +#endif /* LINUX_KASAN_H */ -- cgit v1.2.3