Using the ASAN fibre API is essential, so the cooperative scheduling we implement on top isn't flagged by AddressSanitizer. To prepare using that code elsewhere later, move it to a common header. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- arch/Kconfig | 3 ++ arch/arm/include/asm/setjmp.h | 2 + arch/kvx/include/asm/setjmp.h | 2 + arch/mips/include/asm/setjmp.h | 2 + arch/openrisc/include/asm/setjmp.h | 2 + arch/powerpc/include/asm/setjmp.h | 2 + arch/riscv/include/asm/setjmp.h | 2 + arch/sandbox/Kconfig | 1 + arch/sandbox/include/asm/setjmp.h | 42 ++++++++++++++++++++ arch/x86/include/asm/setjmp.h | 2 + common/bthread.c | 64 ++++++++---------------------- include/asm-generic/setjmp.h | 27 +++++++++++++ 12 files changed, 104 insertions(+), 47 deletions(-) create mode 100644 include/asm-generic/setjmp.h diff --git a/arch/Kconfig b/arch/Kconfig index ad47dbf78d6c..671e6a0e979d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -18,3 +18,6 @@ config ARCH_HAS_CTRLC # config ARCH_DMA_DEFAULT_COHERENT bool + +config ARCH_HAS_ASAN_FIBER_API + bool diff --git a/arch/arm/include/asm/setjmp.h b/arch/arm/include/asm/setjmp.h index 0cee5bfdda60..d28235e56c36 100644 --- a/arch/arm/include/asm/setjmp.h +++ b/arch/arm/include/asm/setjmp.h @@ -28,4 +28,6 @@ void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#include <asm-generic/setjmp.h> + #endif /* _SETJMP_H_ */ diff --git a/arch/kvx/include/asm/setjmp.h b/arch/kvx/include/asm/setjmp.h index 3c23576e6e82..7a09b182f251 100644 --- a/arch/kvx/include/asm/setjmp.h +++ b/arch/kvx/include/asm/setjmp.h @@ -12,4 +12,6 @@ int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *sta int setjmp(jmp_buf jmp) __attribute__((returns_twice)); void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); +#include <asm-generic/setjmp.h> + #endif /* _ASM_KVX_SETJMP_H_ */ diff --git a/arch/mips/include/asm/setjmp.h b/arch/mips/include/asm/setjmp.h index 39e01e27dfc0..af25678573e7 100644 --- a/arch/mips/include/asm/setjmp.h +++ b/arch/mips/include/asm/setjmp.h @@ -29,4 +29,6 @@ int setjmp(jmp_buf jmp) __attribute__((returns_twice)); void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#include <asm-generic/setjmp.h> + #endif /* _MIPS_BITS_SETJMP_H */ diff --git a/arch/openrisc/include/asm/setjmp.h b/arch/openrisc/include/asm/setjmp.h index ee73306d189d..d652e8a3cbcc 100644 --- a/arch/openrisc/include/asm/setjmp.h +++ b/arch/openrisc/include/asm/setjmp.h @@ -14,4 +14,6 @@ int setjmp(jmp_buf jmp) __attribute__((returns_twice)); void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#include <asm-generic/setjmp.h> + #endif /* _OR1K_BITS_SETJMP_H */ diff --git a/arch/powerpc/include/asm/setjmp.h b/arch/powerpc/include/asm/setjmp.h index 91bfcdb7f442..1ece16bb7ea7 100644 --- a/arch/powerpc/include/asm/setjmp.h +++ b/arch/powerpc/include/asm/setjmp.h @@ -18,4 +18,6 @@ void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#include <asm-generic/setjmp.h> + #endif /* _SETJMP_H_ */ diff --git a/arch/riscv/include/asm/setjmp.h b/arch/riscv/include/asm/setjmp.h index 468fc4b10aaf..6604ba402bd9 100644 --- a/arch/riscv/include/asm/setjmp.h +++ b/arch/riscv/include/asm/setjmp.h @@ -24,4 +24,6 @@ void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#include <asm-generic/setjmp.h> + #endif /* _SETJMP_H_ */ diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index d4379c4d68db..932bfd15d212 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,6 +43,7 @@ config 64BIT default CC_IS_64BIT select ARCH_DMA_ADDR_T_64BIT select PHYS_ADDR_T_64BIT + select ARCH_HAS_ASAN_FIBER_API if ASAN config 32BIT def_bool !64BIT diff --git a/arch/sandbox/include/asm/setjmp.h b/arch/sandbox/include/asm/setjmp.h index dcc3b4e86712..65a6d5aafa87 100644 --- a/arch/sandbox/include/asm/setjmp.h +++ b/arch/sandbox/include/asm/setjmp.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file is included both in arch/sandbox/os along with + * system headers and outside with barebox headers, so we avoid + * including any other headers here. + */ #ifndef __SETJMP_H_ #define __SETJMP_H_ @@ -14,4 +19,41 @@ void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)); int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top); +#define start_switch_fiber start_switch_fiber +#define finish_switch_fiber finish_switch_fiber + +void __sanitizer_start_switch_fiber(void **fake_stack_save, + const void *bottom, size_t size) + __attribute__((visibility("default"))); + +void __sanitizer_finish_switch_fiber(void *fake_stack_save, + const void **bottom_old, size_t *size_old) + __attribute__((visibility("default"))); + +static inline void finish_switch_fiber(void *fake_stack_save, + void **initial_bottom, + unsigned *initial_stack_size) +{ +#ifdef CONFIG_ARCH_HAS_ASAN_FIBER_API + const void *bottom_old; + size_t size_old; + + __sanitizer_finish_switch_fiber(fake_stack_save, + &bottom_old, &size_old); + + if (initial_bottom && !*initial_bottom) { + *initial_bottom = (void *)bottom_old; + *initial_stack_size = size_old; + } +#endif +} + +static inline void start_switch_fiber(void **fake_stack_save, + const void *bottom, unsigned size) +{ +#ifdef CONFIG_ARCH_HAS_ASAN_FIBER_API + __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); +#endif +} + #endif diff --git a/arch/x86/include/asm/setjmp.h b/arch/x86/include/asm/setjmp.h index 5af5e624895c..e0f5771b06ba 100644 --- a/arch/x86/include/asm/setjmp.h +++ b/arch/x86/include/asm/setjmp.h @@ -41,4 +41,6 @@ void longjmp(jmp_buf jmp, int ret) __attribute__((noreturn)) __sjlj_attr; int initjmp(jmp_buf jmp, void __attribute__((noreturn)) (*func)(void), void *stack_top) __sjlj_attr; +#include <asm-generic/setjmp.h> + #endif diff --git a/common/bthread.c b/common/bthread.c index d40c0b0f9e3a..943f4c22b346 100644 --- a/common/bthread.c +++ b/common/bthread.c @@ -15,10 +15,6 @@ #include <asm/setjmp.h> #include <linux/overflow.h> -#if defined CONFIG_ASAN && !defined CONFIG_32BIT -#define HAVE_FIBER_SANITIZER -#endif - static struct bthread { void (*threadfn)(void *); void *data; @@ -27,7 +23,7 @@ static struct bthread { void *stack; u32 stack_size; struct list_head list; -#ifdef HAVE_FIBER_SANITIZER +#ifdef CONFIG_ARCH_HAS_ASAN_FIBER_API void *fake_stack_save; #endif u8 awake :1; @@ -45,12 +41,22 @@ struct bthread *current = &main_thread; /* * When using ASAN, it needs to be told when we switch stacks. */ -static void start_switch_fiber(struct bthread *, bool terminate_old); -static void finish_switch_fiber(struct bthread *); +static void bthread_finish_switch_fiber(struct bthread *bthread) +{ + finish_switch_fiber(bthread->fake_stack_save, + &main_thread.stack, &main_thread.stack_size); +} + +static void bthread_start_switch_fiber(struct bthread *to, bool terminate_old) +{ + start_switch_fiber(terminate_old ? &to->fake_stack_save : NULL, + to->stack, to->stack_size); +} static void __noreturn bthread_trampoline(void) { - finish_switch_fiber(current); + bthread_finish_switch_fiber(current); + bthread_reschedule(); current->threadfn(current->data); @@ -59,7 +65,7 @@ static void __noreturn bthread_trampoline(void) current->has_stopped = true; current = &main_thread; - start_switch_fiber(current, true); + bthread_start_switch_fiber(current, true); longjmp(current->jmp_buf, 1); } @@ -198,7 +204,7 @@ void bthread_schedule(struct bthread *to) struct bthread *from = current; int ret; - start_switch_fiber(to, false); + bthread_start_switch_fiber(to, false); ret = setjmp(from->jmp_buf); if (ret == 0) { @@ -206,41 +212,5 @@ void bthread_schedule(struct bthread *to) longjmp(to->jmp_buf, 1); } - finish_switch_fiber(from); + bthread_finish_switch_fiber(from); } - -#ifdef HAVE_FIBER_SANITIZER - -void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size); -void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); - -static void finish_switch_fiber(struct bthread *bthread) -{ - const void *bottom_old; - size_t size_old; - - __sanitizer_finish_switch_fiber(bthread->fake_stack_save, &bottom_old, &size_old); - - if (!main_thread.stack) { - main_thread.stack = (void *)bottom_old; - main_thread.stack_size = size_old; - } -} - -static void start_switch_fiber(struct bthread *to, bool terminate_old) -{ - __sanitizer_start_switch_fiber(terminate_old ? &to->fake_stack_save : NULL, - to->stack, to->stack_size); -} - -#else - -static void finish_switch_fiber(struct bthread *bthread) -{ -} - -static void start_switch_fiber(struct bthread *to, bool terminate_old) -{ -} - -#endif diff --git a/include/asm-generic/setjmp.h b/include/asm-generic/setjmp.h new file mode 100644 index 000000000000..fb3e85ad5139 --- /dev/null +++ b/include/asm-generic/setjmp.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ASAN bookkeeping based on Qemu coroutine-ucontext.c + */ + +#ifndef __ASM_GENERIC_SETJMP_H_ +#define __ASM_GENERIC_SETJMP_H_ + +#ifndef finish_switch_fiber +#define finish_switch_fiber finish_switch_fiber +static inline void finish_switch_fiber(void *fake_stack_save, + void **initial_bottom, + unsigned *initial_stack_size) +{ +} +#endif + +#ifndef start_switch_fiber +#define start_switch_fiber start_switch_fiber +static inline void start_switch_fiber(void **fake_stack_save, + const void *bottom, unsigned size) +{ +} + +#endif + +#endif -- 2.39.5