[PATCH v2] task_work: kasan: record task_work_add() call stack
Why record task_work_add() call stack? Syzbot reports many use-after-free issues for task_work, see [1]. After see the free stack and the current auxiliary stack, we think they are useless, we don't know where register the work, this work may be the free call stack, so that we miss the root cause and don't solve the use-after-free. Add task_work_add() call stack into KASAN auxiliary stack in order to improve KASAN report. It is useful for programmers to solve use-after-free issues. [1]: https://groups.google.com/g/syzkaller-bugs/search?q=kasan%20use-after-free%20task_work_run Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Matthias Brugger Cc: Jens Axboe Cc: Oleg Nesterov --- v2: Fix kasan_record_aux_stack() calling sequence issue. Thanks for Dmitry's suggestion --- kernel/task_work.c | 3 +++ mm/kasan/kasan.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 9cde961875c0..3d4852891fa8 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -34,6 +34,9 @@ int task_work_add(struct task_struct *task, struct callback_head *work, { struct callback_head *head; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + do { head = READ_ONCE(task->task_works); if (unlikely(head == _exited)) diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 3436c6bf7c0c..e4629a971a3c 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -146,7 +146,7 @@ struct kasan_alloc_meta { struct kasan_track alloc_track; #ifdef CONFIG_KASAN_GENERIC /* -* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The auxiliary stack is stored into struct kasan_alloc_meta. * The free stack is stored into struct kasan_free_meta. */ depot_stack_handle_t aux_stack[2]; -- 2.18.0
Re: [PATCH] task_work: kasan: record task_work_add() call stack
On Mon, 2021-03-15 at 11:03 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > On Mon, Mar 15, 2021 at 10:38 AM Walter Wu wrote: > > > > On Mon, 2021-03-15 at 07:58 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > > > On Mon, Mar 15, 2021 at 3:00 AM Walter Wu > > > wrote: > > > > > > > > Why record task_work_add() call stack? > > > > Syzbot reports many use-after-free issues for task_work, see [1]. > > > > After see the free stack and the current auxiliary stack, we think > > > > they are useless, we don't know where register the work, this work > > > > may be the free call stack, so that we miss the root cause and > > > > don't solve the use-after-free. > > > > > > > > Add task_work_add() call stack into KASAN auxiliary stack in > > > > order to improve KASAN report. It is useful for programmers > > > > to solve use-after-free issues. > > > > > > > > [1]: > > > > https://groups.google.com/g/syzkaller-bugs/search?q=kasan%20use-after-free%20task_work_run > > > > > > > > Signed-off-by: Walter Wu > > > > Suggested-by: Dmitry Vyukov > > > > Cc: Andrey Ryabinin > > > > Cc: Dmitry Vyukov > > > > Cc: Andrey Konovalov > > > > Cc: Alexander Potapenko > > > > Cc: Andrew Morton > > > > Cc: Matthias Brugger > > > > Cc: Jens Axboe > > > > Cc: Oleg Nesterov > > > > --- > > > > kernel/task_work.c | 3 +++ > > > > mm/kasan/kasan.h | 2 +- > > > > 2 files changed, 4 insertions(+), 1 deletion(-) > > > > > > > > diff --git a/kernel/task_work.c b/kernel/task_work.c > > > > index 9cde961875c0..f255294377da 100644 > > > > --- a/kernel/task_work.c > > > > +++ b/kernel/task_work.c > > > > @@ -55,6 +55,9 @@ int task_work_add(struct task_struct *task, struct > > > > callback_head *work, > > > > break; > > > > } > > > > > > > > + /* record the work call stack in order to print it in KASAN > > > > reports */ > > > > + kasan_record_aux_stack(work); > > > > > > I think this call should be done _before_ we actually queue the work, > > > because this function may operate on non-current task. > > > Consider, we queue the work, the other task already executes it and > > > triggers use-after-free, now only now we record the stack. > > > > agree, what do you think below change? > > > > --- a/kernel/task_work.c > > +++ b/kernel/task_work.c > > @@ -34,6 +34,9 @@ int task_work_add(struct task_struct *task, struct > > callback_head *work, > > { > > struct callback_head *head; > > > > + /* record the work call stack in order to print it in KASAN reports > > */ > > + kasan_record_aux_stack(work); > > + > > This looks good to me. > > > > do { > > head = READ_ONCE(task->task_works); > > if (unlikely(head == _exited)) > > @@ -55,9 +58,6 @@ int task_work_add(struct task_struct *task, struct > > callback_head *work, > > break; > > } > > > > - /* record the work call stack in order to print it in KASAN reports > > */ > > - kasan_record_aux_stack(work); > > - > > return 0; > > } > > > > > Moreover, I think we can trigger use-after-free here ourselves while > > > recording the aux stack. We queued the work, and the work can cause > > > own free, so it's not necessary live by now. > > > > Sorry, I don't fully know your meaning, do you mean we should add an > > abort when detect use-after-free? > > I meant that where we had the kasan_record_aux_stack(work) call in the > first version of the patch, work can be already freed. We must not > access work after queueing it. > Got it. Now I must treat urgent issue, I will send v2 patch tomorrow. Thanks for your review. > > > > return 0; > > > > } > > > > > > > > diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h > > > > index 3436c6bf7c0c..d300fe9415bd 100644 > > > > --- a/mm/kasan/kasan.h > > > > +++ b/mm/kasan/kasan.h > > > > @@ -146,7 +146,7 @@ struct kasan_alloc_meta { > > > > struct kasan_track alloc_track; > > > > #ifdef CONFIG_KASAN_GENERIC > > > > /* > > > > -* call_rcu() call stack is stored into struct kasan_alloc_meta. > > > > +* Auxiliary stack is stored into struct kasan_alloc_meta. > > > > * The free stack is stored into struct kasan_free_meta. > > > > */ > > > > depot_stack_handle_t aux_stack[2]; > > > > -- > > > > 2.18.0 > > > > > > > -- > > You received this message because you are subscribed to the Google Groups > > "kasan-dev" group. > > To unsubscribe from this group and stop receiving emails from it, send an > > email to kasan-dev+unsubscr...@googlegroups.com. > > To view this discussion on the web visit > > https://groups.google.com/d/msgid/kasan-dev/1615801102.24887.4.camel%40mtksdccf07. >
Re: [PATCH] task_work: kasan: record task_work_add() call stack
On Mon, 2021-03-15 at 07:58 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > On Mon, Mar 15, 2021 at 3:00 AM Walter Wu wrote: > > > > Why record task_work_add() call stack? > > Syzbot reports many use-after-free issues for task_work, see [1]. > > After see the free stack and the current auxiliary stack, we think > > they are useless, we don't know where register the work, this work > > may be the free call stack, so that we miss the root cause and > > don't solve the use-after-free. > > > > Add task_work_add() call stack into KASAN auxiliary stack in > > order to improve KASAN report. It is useful for programmers > > to solve use-after-free issues. > > > > [1]: > > https://groups.google.com/g/syzkaller-bugs/search?q=kasan%20use-after-free%20task_work_run > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Andrey Konovalov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > Cc: Matthias Brugger > > Cc: Jens Axboe > > Cc: Oleg Nesterov > > --- > > kernel/task_work.c | 3 +++ > > mm/kasan/kasan.h | 2 +- > > 2 files changed, 4 insertions(+), 1 deletion(-) > > > > diff --git a/kernel/task_work.c b/kernel/task_work.c > > index 9cde961875c0..f255294377da 100644 > > --- a/kernel/task_work.c > > +++ b/kernel/task_work.c > > @@ -55,6 +55,9 @@ int task_work_add(struct task_struct *task, struct > > callback_head *work, > > break; > > } > > > > + /* record the work call stack in order to print it in KASAN reports > > */ > > + kasan_record_aux_stack(work); > > I think this call should be done _before_ we actually queue the work, > because this function may operate on non-current task. > Consider, we queue the work, the other task already executes it and > triggers use-after-free, now only now we record the stack. agree, what do you think below change? --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -34,6 +34,9 @@ int task_work_add(struct task_struct *task, struct callback_head *work, { struct callback_head *head; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + do { head = READ_ONCE(task->task_works); if (unlikely(head == _exited)) @@ -55,9 +58,6 @@ int task_work_add(struct task_struct *task, struct callback_head *work, break; } - /* record the work call stack in order to print it in KASAN reports */ - kasan_record_aux_stack(work); - return 0; } > Moreover, I think we can trigger use-after-free here ourselves while > recording the aux stack. We queued the work, and the work can cause > own free, so it's not necessary live by now. Sorry, I don't fully know your meaning, do you mean we should add an abort when detect use-after-free? > > > return 0; > > } > > > > diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h > > index 3436c6bf7c0c..d300fe9415bd 100644 > > --- a/mm/kasan/kasan.h > > +++ b/mm/kasan/kasan.h > > @@ -146,7 +146,7 @@ struct kasan_alloc_meta { > > struct kasan_track alloc_track; > > #ifdef CONFIG_KASAN_GENERIC > > /* > > -* call_rcu() call stack is stored into struct kasan_alloc_meta. > > +* Auxiliary stack is stored into struct kasan_alloc_meta. > > * The free stack is stored into struct kasan_free_meta. > > */ > > depot_stack_handle_t aux_stack[2]; > > -- > > 2.18.0 >
[PATCH] task_work: kasan: record task_work_add() call stack
Why record task_work_add() call stack? Syzbot reports many use-after-free issues for task_work, see [1]. After see the free stack and the current auxiliary stack, we think they are useless, we don't know where register the work, this work may be the free call stack, so that we miss the root cause and don't solve the use-after-free. Add task_work_add() call stack into KASAN auxiliary stack in order to improve KASAN report. It is useful for programmers to solve use-after-free issues. [1]: https://groups.google.com/g/syzkaller-bugs/search?q=kasan%20use-after-free%20task_work_run Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Matthias Brugger Cc: Jens Axboe Cc: Oleg Nesterov --- kernel/task_work.c | 3 +++ mm/kasan/kasan.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 9cde961875c0..f255294377da 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -55,6 +55,9 @@ int task_work_add(struct task_struct *task, struct callback_head *work, break; } + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + return 0; } diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 3436c6bf7c0c..d300fe9415bd 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -146,7 +146,7 @@ struct kasan_alloc_meta { struct kasan_track alloc_track; #ifdef CONFIG_KASAN_GENERIC /* -* call_rcu() call stack is stored into struct kasan_alloc_meta. +* Auxiliary stack is stored into struct kasan_alloc_meta. * The free stack is stored into struct kasan_free_meta. */ depot_stack_handle_t aux_stack[2]; -- 2.18.0
Re: [PATCH v4] kasan: remove redundant config option
On Wed, 2021-03-03 at 19:48 +0800, Walter Wu wrote: > On Fri, 2021-02-26 at 09:25 +0800, Walter Wu wrote: > > CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack > > instrumentation, but we should only need one config, so that we remove > > CONFIG_KASAN_STACK_ENABLE and make CONFIG_KASAN_STACK workable. see [1]. > > > > When enable KASAN stack instrumentation, then for gcc we could do no > > prompt and default value y, and for clang prompt and default value n. > > > > [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Reviewed-by: Nathan Chancellor > > Acked-by: Arnd Bergmann > > Reviewed-by: Andrey Konovalov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > --- > > > > v4: After this patch sent, someone had modification about KASAN_STACK, > > so I need to rebase codebase. Thank Andrey for your pointing. > > > Hi Andrew, > > Could you pick this v4 patch up into mm? > Thanks. > > Walter > > > --- > > arch/arm64/kernel/sleep.S| 2 +- > > arch/x86/kernel/acpi/wakeup_64.S | 2 +- > > include/linux/kasan.h| 2 +- > > lib/Kconfig.kasan| 8 ++-- > > mm/kasan/common.c| 2 +- > > mm/kasan/kasan.h | 2 +- > > mm/kasan/report_generic.c| 2 +- > > scripts/Makefile.kasan | 10 -- > > security/Kconfig.hardening | 4 ++-- > > 9 files changed, 18 insertions(+), 16 deletions(-) > > > > diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S > > index 5bfd9b87f85d..4ea9392f86e0 100644 > > --- a/arch/arm64/kernel/sleep.S > > +++ b/arch/arm64/kernel/sleep.S > > @@ -134,7 +134,7 @@ SYM_FUNC_START(_cpu_resume) > > */ > > bl cpu_do_resume > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > mov x0, sp > > bl kasan_unpoison_task_stack_below > > #endif > > diff --git a/arch/x86/kernel/acpi/wakeup_64.S > > b/arch/x86/kernel/acpi/wakeup_64.S > > index 56b6865afb2a..d5d8a352eafa 100644 > > --- a/arch/x86/kernel/acpi/wakeup_64.S > > +++ b/arch/x86/kernel/acpi/wakeup_64.S > > @@ -115,7 +115,7 @@ SYM_FUNC_START(do_suspend_lowlevel) > > movqpt_regs_r14(%rax), %r14 > > movqpt_regs_r15(%rax), %r15 > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > /* > > * The suspend path may have poisoned some areas deeper in the stack, > > * which we now need to unpoison. > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index b91732bd05d7..14f72ec96492 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -330,7 +330,7 @@ static inline bool kasan_check_byte(const void *address) > > > > #endif /* CONFIG_KASAN */ > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > void kasan_unpoison_task_stack(struct task_struct *task); > > #else > > static inline void kasan_unpoison_task_stack(struct task_struct *task) {} > > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > > index 624ae1df7984..cffc2ebbf185 100644 > > --- a/lib/Kconfig.kasan > > +++ b/lib/Kconfig.kasan > > @@ -138,9 +138,10 @@ config KASAN_INLINE > > > > endchoice > > > > -config KASAN_STACK_ENABLE > > +config KASAN_STACK > > bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && > > !COMPILE_TEST > > depends on KASAN_GENERIC || KASAN_SW_TAGS > > + default y if CC_IS_GCC > > help > > The LLVM stack address sanitizer has a know problem that > > causes excessive stack usage in a lot of functions, see > > @@ -154,11 +155,6 @@ config KASAN_STACK_ENABLE > > CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe > > to use and enabled by default. > > > > -config KASAN_STACK > > - int > > - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC > > - default 0 > > - Hi Andrew, I see my v4 patch is different in the next tree now. please see below information. https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=ebced5fb0ef969620e
Re: [PATCH v4] kasan: remove redundant config option
On Fri, 2021-02-26 at 09:25 +0800, Walter Wu wrote: > CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack > instrumentation, but we should only need one config, so that we remove > CONFIG_KASAN_STACK_ENABLE and make CONFIG_KASAN_STACK workable. see [1]. > > When enable KASAN stack instrumentation, then for gcc we could do no > prompt and default value y, and for clang prompt and default value n. > > [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 > > Signed-off-by: Walter Wu > Suggested-by: Dmitry Vyukov > Reviewed-by: Nathan Chancellor > Acked-by: Arnd Bergmann > Reviewed-by: Andrey Konovalov > Cc: Andrey Ryabinin > Cc: Dmitry Vyukov > Cc: Alexander Potapenko > Cc: Andrew Morton > --- > > v4: After this patch sent, someone had modification about KASAN_STACK, > so I need to rebase codebase. Thank Andrey for your pointing. > Hi Andrew, Could you pick this v4 patch up into mm? Thanks. Walter > --- > arch/arm64/kernel/sleep.S| 2 +- > arch/x86/kernel/acpi/wakeup_64.S | 2 +- > include/linux/kasan.h| 2 +- > lib/Kconfig.kasan| 8 ++-- > mm/kasan/common.c| 2 +- > mm/kasan/kasan.h | 2 +- > mm/kasan/report_generic.c| 2 +- > scripts/Makefile.kasan | 10 -- > security/Kconfig.hardening | 4 ++-- > 9 files changed, 18 insertions(+), 16 deletions(-) > > diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S > index 5bfd9b87f85d..4ea9392f86e0 100644 > --- a/arch/arm64/kernel/sleep.S > +++ b/arch/arm64/kernel/sleep.S > @@ -134,7 +134,7 @@ SYM_FUNC_START(_cpu_resume) >*/ > bl cpu_do_resume > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > mov x0, sp > bl kasan_unpoison_task_stack_below > #endif > diff --git a/arch/x86/kernel/acpi/wakeup_64.S > b/arch/x86/kernel/acpi/wakeup_64.S > index 56b6865afb2a..d5d8a352eafa 100644 > --- a/arch/x86/kernel/acpi/wakeup_64.S > +++ b/arch/x86/kernel/acpi/wakeup_64.S > @@ -115,7 +115,7 @@ SYM_FUNC_START(do_suspend_lowlevel) > movqpt_regs_r14(%rax), %r14 > movqpt_regs_r15(%rax), %r15 > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > /* >* The suspend path may have poisoned some areas deeper in the stack, >* which we now need to unpoison. > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > index b91732bd05d7..14f72ec96492 100644 > --- a/include/linux/kasan.h > +++ b/include/linux/kasan.h > @@ -330,7 +330,7 @@ static inline bool kasan_check_byte(const void *address) > > #endif /* CONFIG_KASAN */ > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > void kasan_unpoison_task_stack(struct task_struct *task); > #else > static inline void kasan_unpoison_task_stack(struct task_struct *task) {} > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > index 624ae1df7984..cffc2ebbf185 100644 > --- a/lib/Kconfig.kasan > +++ b/lib/Kconfig.kasan > @@ -138,9 +138,10 @@ config KASAN_INLINE > > endchoice > > -config KASAN_STACK_ENABLE > +config KASAN_STACK > bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && > !COMPILE_TEST > depends on KASAN_GENERIC || KASAN_SW_TAGS > + default y if CC_IS_GCC > help > The LLVM stack address sanitizer has a know problem that > causes excessive stack usage in a lot of functions, see > @@ -154,11 +155,6 @@ config KASAN_STACK_ENABLE > CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe > to use and enabled by default. > > -config KASAN_STACK > - int > - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC > - default 0 > - > config KASAN_SW_TAGS_IDENTIFY > bool "Enable memory corruption identification" > depends on KASAN_SW_TAGS > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > index b5e08d4cefec..7b53291dafa1 100644 > --- a/mm/kasan/common.c > +++ b/mm/kasan/common.c > @@ -63,7 +63,7 @@ void __kasan_unpoison_range(const void *address, size_t > size) > kasan_unpoison(address, size); > } > > -#if CONFIG_KASAN_STACK > +#ifdef CONFIG_KASAN_STACK > /* Unpoison the entire stack for a task. */ > void kasan_unpoison_task_stack(struct task_struct *task) > { > diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h > index 8c55634d6edd..3436c6bf7c0c 100644 > --- a/mm/kasa
[PATCH v4] kasan: remove redundant config option
CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack instrumentation, but we should only need one config, so that we remove CONFIG_KASAN_STACK_ENABLE and make CONFIG_KASAN_STACK workable. see [1]. When enable KASAN stack instrumentation, then for gcc we could do no prompt and default value y, and for clang prompt and default value n. [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Reviewed-by: Nathan Chancellor Acked-by: Arnd Bergmann Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrew Morton --- v4: After this patch sent, someone had modification about KASAN_STACK, so I need to rebase codebase. Thank Andrey for your pointing. --- arch/arm64/kernel/sleep.S| 2 +- arch/x86/kernel/acpi/wakeup_64.S | 2 +- include/linux/kasan.h| 2 +- lib/Kconfig.kasan| 8 ++-- mm/kasan/common.c| 2 +- mm/kasan/kasan.h | 2 +- mm/kasan/report_generic.c| 2 +- scripts/Makefile.kasan | 10 -- security/Kconfig.hardening | 4 ++-- 9 files changed, 18 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 5bfd9b87f85d..4ea9392f86e0 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -134,7 +134,7 @@ SYM_FUNC_START(_cpu_resume) */ bl cpu_do_resume -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) mov x0, sp bl kasan_unpoison_task_stack_below #endif diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 56b6865afb2a..d5d8a352eafa 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -115,7 +115,7 @@ SYM_FUNC_START(do_suspend_lowlevel) movqpt_regs_r14(%rax), %r14 movqpt_regs_r15(%rax), %r15 -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) /* * The suspend path may have poisoned some areas deeper in the stack, * which we now need to unpoison. diff --git a/include/linux/kasan.h b/include/linux/kasan.h index b91732bd05d7..14f72ec96492 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -330,7 +330,7 @@ static inline bool kasan_check_byte(const void *address) #endif /* CONFIG_KASAN */ -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) void kasan_unpoison_task_stack(struct task_struct *task); #else static inline void kasan_unpoison_task_stack(struct task_struct *task) {} diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index 624ae1df7984..cffc2ebbf185 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -138,9 +138,10 @@ config KASAN_INLINE endchoice -config KASAN_STACK_ENABLE +config KASAN_STACK bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST depends on KASAN_GENERIC || KASAN_SW_TAGS + default y if CC_IS_GCC help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see @@ -154,11 +155,6 @@ config KASAN_STACK_ENABLE CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe to use and enabled by default. -config KASAN_STACK - int - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC - default 0 - config KASAN_SW_TAGS_IDENTIFY bool "Enable memory corruption identification" depends on KASAN_SW_TAGS diff --git a/mm/kasan/common.c b/mm/kasan/common.c index b5e08d4cefec..7b53291dafa1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -63,7 +63,7 @@ void __kasan_unpoison_range(const void *address, size_t size) kasan_unpoison(address, size); } -#if CONFIG_KASAN_STACK +#ifdef CONFIG_KASAN_STACK /* Unpoison the entire stack for a task. */ void kasan_unpoison_task_stack(struct task_struct *task) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 8c55634d6edd..3436c6bf7c0c 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -231,7 +231,7 @@ void *kasan_find_first_bad_addr(void *addr, size_t size); const char *kasan_get_bug_type(struct kasan_access_info *info); void kasan_metadata_fetch_row(char *buffer, void *row); -#if defined(CONFIG_KASAN_GENERIC) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_GENERIC) && defined(CONFIG_KASAN_STACK) void kasan_print_address_stack_frame(const void *addr); #else static inline void kasan_print_address_stack_frame(const void *addr) { } diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c index 41f374585144..de732bc341c5 100644 --- a/mm/kasan/report_generic.c +++ b/mm/kasan/report_generic.c @@ -
[PATCH v3] kasan: remove redundant config option
CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack instrumentation, but we should only need one config, so that we remove CONFIG_KASAN_STACK_ENABLE and make CONFIG_KASAN_STACK workable. see [1]. When enable KASAN stack instrumentation, then for gcc we could do no prompt and default value y, and for clang prompt and default value n. [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Nathan Chancellor --- v2: make commit log to be more readable. v3: remain CONFIG_KASAN_STACK_ENABLE setting fix the pre-processors syntax --- arch/arm64/kernel/sleep.S| 2 +- arch/x86/kernel/acpi/wakeup_64.S | 2 +- include/linux/kasan.h| 2 +- lib/Kconfig.kasan| 8 ++-- mm/kasan/common.c| 2 +- mm/kasan/kasan.h | 2 +- mm/kasan/report_generic.c| 2 +- scripts/Makefile.kasan | 10 -- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 6bdef7362c0e..7c44ede122a9 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -133,7 +133,7 @@ SYM_FUNC_START(_cpu_resume) */ bl cpu_do_resume -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) mov x0, sp bl kasan_unpoison_task_stack_below #endif diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 5d3a0b8fd379..c7f412f4e07d 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -112,7 +112,7 @@ SYM_FUNC_START(do_suspend_lowlevel) movqpt_regs_r14(%rax), %r14 movqpt_regs_r15(%rax), %r15 -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) /* * The suspend path may have poisoned some areas deeper in the stack, * which we now need to unpoison. diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 5e0655fb2a6f..35d1e9b2cbfa 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -302,7 +302,7 @@ static inline void kasan_kfree_large(void *ptr, unsigned long ip) {} #endif /* CONFIG_KASAN */ -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) void kasan_unpoison_task_stack(struct task_struct *task); #else static inline void kasan_unpoison_task_stack(struct task_struct *task) {} diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index f5fa4ba126bf..fde82ec85f8f 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -138,9 +138,10 @@ config KASAN_INLINE endchoice -config KASAN_STACK_ENABLE +config KASAN_STACK bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST depends on KASAN_GENERIC || KASAN_SW_TAGS + default y if CC_IS_GCC help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see @@ -154,11 +155,6 @@ config KASAN_STACK_ENABLE CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe to use and enabled by default. -config KASAN_STACK - int - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC - default 0 - config KASAN_SW_TAGS_IDENTIFY bool "Enable memory corruption identification" depends on KASAN_SW_TAGS diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 38ba2aecd8f4..bf8b073eed62 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -63,7 +63,7 @@ void __kasan_unpoison_range(const void *address, size_t size) unpoison_range(address, size); } -#if CONFIG_KASAN_STACK +#ifdef CONFIG_KASAN_STACK /* Unpoison the entire stack for a task. */ void kasan_unpoison_task_stack(struct task_struct *task) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index cc4d9e1d49b1..bdfdb1cff653 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -224,7 +224,7 @@ void *find_first_bad_addr(void *addr, size_t size); const char *get_bug_type(struct kasan_access_info *info); void metadata_fetch_row(char *buffer, void *row); -#if defined(CONFIG_KASAN_GENERIC) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_GENERIC) && defined(CONFIG_KASAN_STACK) void print_address_stack_frame(const void *addr); #else static inline void print_address_stack_frame(const void *addr) { } diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c index 8a9c889872da..4e16518d9877 100644 --- a/mm/kasan/report_generic.c +++ b/mm/kasan/report_generic.c @@ -128,7 +128,7 @@ void metadata_fetch_row(char *buffer, void *row) memcpy(buffer, kasan_mem_to_shadow(row
Re: [PATCH] kasan: remove redundant config option
On Thu, 2021-01-07 at 14:00 -0700, Nathan Chancellor wrote: > On Thu, Jan 07, 2021 at 02:21:52PM +0800, Walter Wu wrote: > > CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN > > stack instrumentation, but we should only need one config option, > > so that we remove CONFIG_KASAN_STACK_ENABLE. see [1]. > > > > For gcc we could do no prompt and default value y, and for clang > > prompt and default value n. > > > > [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Andrey Konovalov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > --- > > arch/arm64/kernel/sleep.S| 2 +- > > arch/x86/kernel/acpi/wakeup_64.S | 2 +- > > include/linux/kasan.h| 2 +- > > lib/Kconfig.kasan| 11 --- > > mm/kasan/common.c| 2 +- > > mm/kasan/kasan.h | 2 +- > > mm/kasan/report_generic.c| 2 +- > > scripts/Makefile.kasan | 10 -- > > 8 files changed, 18 insertions(+), 15 deletions(-) > > > > diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S > > index 6bdef7362c0e..7c44ede122a9 100644 > > --- a/arch/arm64/kernel/sleep.S > > +++ b/arch/arm64/kernel/sleep.S > > @@ -133,7 +133,7 @@ SYM_FUNC_START(_cpu_resume) > > */ > > bl cpu_do_resume > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > mov x0, sp > > bl kasan_unpoison_task_stack_below > > #endif > > diff --git a/arch/x86/kernel/acpi/wakeup_64.S > > b/arch/x86/kernel/acpi/wakeup_64.S > > index 5d3a0b8fd379..c7f412f4e07d 100644 > > --- a/arch/x86/kernel/acpi/wakeup_64.S > > +++ b/arch/x86/kernel/acpi/wakeup_64.S > > @@ -112,7 +112,7 @@ SYM_FUNC_START(do_suspend_lowlevel) > > movqpt_regs_r14(%rax), %r14 > > movqpt_regs_r15(%rax), %r15 > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > /* > > * The suspend path may have poisoned some areas deeper in the stack, > > * which we now need to unpoison. > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 5e0655fb2a6f..35d1e9b2cbfa 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -302,7 +302,7 @@ static inline void kasan_kfree_large(void *ptr, > > unsigned long ip) {} > > > > #endif /* CONFIG_KASAN */ > > > > -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK > > +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) > > void kasan_unpoison_task_stack(struct task_struct *task); > > #else > > static inline void kasan_unpoison_task_stack(struct task_struct *task) {} > > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > > index f5fa4ba126bf..59de74293454 100644 > > --- a/lib/Kconfig.kasan > > +++ b/lib/Kconfig.kasan > > @@ -138,9 +138,11 @@ config KASAN_INLINE > > > > endchoice > > > > -config KASAN_STACK_ENABLE > > - bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && > > !COMPILE_TEST > > You are effectively undoing commits 6baec880d7a5 ("kasan: turn off > asan-stack for clang-8 and earlier") and ebb6d35a74ce ("kasan: remove > clang version check for KASAN_STACK") with this change. This change > should still remain around so that all{mod,yes}config remain mostly > clean for clang builds. This should not change anything from the user's > perspective because this option was never user selectable for GCC and > the default y keeps it on. > Ok, I will remain this. > > +config KASAN_STACK > > + bool "Enable stack instrumentation (unsafe)" > > depends on KASAN_GENERIC || KASAN_SW_TAGS > > + default y if CC_IS_GCC > > + default n if CC_IS_CLANG > > This is implied and can be removed. > > > help > > The LLVM stack address sanitizer has a know problem that > > causes excessive stack usage in a lot of functions, see > > @@ -154,11 +156,6 @@ config KASAN_STACK_ENABLE > > CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe > > to use and enabled by default. > > > > -config KASAN_STACK > > - int > > - default 1 if KASAN_STACK_ENABLE || CC_I
[PATCH v2] kasan: remove redundant config option
CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack instrumentation, but we should only need one config, so that we remove CONFIG_KASAN_STACK_ENABLE and make CONFIG_KASAN_STACK workable. see [1]. When enable KASAN stack instrumentation, then for gcc we could do no prompt and default value y, and for clang prompt and default value n. [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrew Morton --- v2: make commit log to be more readable. --- arch/arm64/kernel/sleep.S| 2 +- arch/x86/kernel/acpi/wakeup_64.S | 2 +- include/linux/kasan.h| 2 +- lib/Kconfig.kasan| 11 --- mm/kasan/common.c| 2 +- mm/kasan/kasan.h | 2 +- mm/kasan/report_generic.c| 2 +- scripts/Makefile.kasan | 10 -- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 6bdef7362c0e..7c44ede122a9 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -133,7 +133,7 @@ SYM_FUNC_START(_cpu_resume) */ bl cpu_do_resume -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) mov x0, sp bl kasan_unpoison_task_stack_below #endif diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 5d3a0b8fd379..c7f412f4e07d 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -112,7 +112,7 @@ SYM_FUNC_START(do_suspend_lowlevel) movqpt_regs_r14(%rax), %r14 movqpt_regs_r15(%rax), %r15 -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) /* * The suspend path may have poisoned some areas deeper in the stack, * which we now need to unpoison. diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 5e0655fb2a6f..35d1e9b2cbfa 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -302,7 +302,7 @@ static inline void kasan_kfree_large(void *ptr, unsigned long ip) {} #endif /* CONFIG_KASAN */ -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) void kasan_unpoison_task_stack(struct task_struct *task); #else static inline void kasan_unpoison_task_stack(struct task_struct *task) {} diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index f5fa4ba126bf..59de74293454 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -138,9 +138,11 @@ config KASAN_INLINE endchoice -config KASAN_STACK_ENABLE - bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST +config KASAN_STACK + bool "Enable stack instrumentation (unsafe)" depends on KASAN_GENERIC || KASAN_SW_TAGS + default y if CC_IS_GCC + default n if CC_IS_CLANG help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see @@ -154,11 +156,6 @@ config KASAN_STACK_ENABLE CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe to use and enabled by default. -config KASAN_STACK - int - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC - default 0 - config KASAN_SW_TAGS_IDENTIFY bool "Enable memory corruption identification" depends on KASAN_SW_TAGS diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 38ba2aecd8f4..02ec7f81dc16 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -63,7 +63,7 @@ void __kasan_unpoison_range(const void *address, size_t size) unpoison_range(address, size); } -#if CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_STACK) /* Unpoison the entire stack for a task. */ void kasan_unpoison_task_stack(struct task_struct *task) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index cc4d9e1d49b1..bdfdb1cff653 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -224,7 +224,7 @@ void *find_first_bad_addr(void *addr, size_t size); const char *get_bug_type(struct kasan_access_info *info); void metadata_fetch_row(char *buffer, void *row); -#if defined(CONFIG_KASAN_GENERIC) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_GENERIC) && defined(CONFIG_KASAN_STACK) void print_address_stack_frame(const void *addr); #else static inline void print_address_stack_frame(const void *addr) { } diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c index 8a9c889872da..137a1dba1978 100644 --- a/mm/kasan/report_generic.c +++ b/mm/kasan/report_generic.c @@ -128,7 +128,7 @@ void metadata_fetch_row(char *buffer, void *row) memcpy(buffer, kasan_mem_to_shadow(row), META_B
[PATCH] kasan: remove redundant config option
CONFIG_KASAN_STACK and CONFIG_KASAN_STACK_ENABLE both enable KASAN stack instrumentation, but we should only need one config option, so that we remove CONFIG_KASAN_STACK_ENABLE. see [1]. For gcc we could do no prompt and default value y, and for clang prompt and default value n. [1]: https://bugzilla.kernel.org/show_bug.cgi?id=210221 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrew Morton --- arch/arm64/kernel/sleep.S| 2 +- arch/x86/kernel/acpi/wakeup_64.S | 2 +- include/linux/kasan.h| 2 +- lib/Kconfig.kasan| 11 --- mm/kasan/common.c| 2 +- mm/kasan/kasan.h | 2 +- mm/kasan/report_generic.c| 2 +- scripts/Makefile.kasan | 10 -- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 6bdef7362c0e..7c44ede122a9 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -133,7 +133,7 @@ SYM_FUNC_START(_cpu_resume) */ bl cpu_do_resume -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) mov x0, sp bl kasan_unpoison_task_stack_below #endif diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 5d3a0b8fd379..c7f412f4e07d 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -112,7 +112,7 @@ SYM_FUNC_START(do_suspend_lowlevel) movqpt_regs_r14(%rax), %r14 movqpt_regs_r15(%rax), %r15 -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) /* * The suspend path may have poisoned some areas deeper in the stack, * which we now need to unpoison. diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 5e0655fb2a6f..35d1e9b2cbfa 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -302,7 +302,7 @@ static inline void kasan_kfree_large(void *ptr, unsigned long ip) {} #endif /* CONFIG_KASAN */ -#if defined(CONFIG_KASAN) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) void kasan_unpoison_task_stack(struct task_struct *task); #else static inline void kasan_unpoison_task_stack(struct task_struct *task) {} diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index f5fa4ba126bf..59de74293454 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -138,9 +138,11 @@ config KASAN_INLINE endchoice -config KASAN_STACK_ENABLE - bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST +config KASAN_STACK + bool "Enable stack instrumentation (unsafe)" depends on KASAN_GENERIC || KASAN_SW_TAGS + default y if CC_IS_GCC + default n if CC_IS_CLANG help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see @@ -154,11 +156,6 @@ config KASAN_STACK_ENABLE CONFIG_COMPILE_TEST. On gcc it is assumed to always be safe to use and enabled by default. -config KASAN_STACK - int - default 1 if KASAN_STACK_ENABLE || CC_IS_GCC - default 0 - config KASAN_SW_TAGS_IDENTIFY bool "Enable memory corruption identification" depends on KASAN_SW_TAGS diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 38ba2aecd8f4..02ec7f81dc16 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -63,7 +63,7 @@ void __kasan_unpoison_range(const void *address, size_t size) unpoison_range(address, size); } -#if CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_STACK) /* Unpoison the entire stack for a task. */ void kasan_unpoison_task_stack(struct task_struct *task) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index cc4d9e1d49b1..bdfdb1cff653 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -224,7 +224,7 @@ void *find_first_bad_addr(void *addr, size_t size); const char *get_bug_type(struct kasan_access_info *info); void metadata_fetch_row(char *buffer, void *row); -#if defined(CONFIG_KASAN_GENERIC) && CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_GENERIC) && defined(CONFIG_KASAN_STACK) void print_address_stack_frame(const void *addr); #else static inline void print_address_stack_frame(const void *addr) { } diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c index 8a9c889872da..137a1dba1978 100644 --- a/mm/kasan/report_generic.c +++ b/mm/kasan/report_generic.c @@ -128,7 +128,7 @@ void metadata_fetch_row(char *buffer, void *row) memcpy(buffer, kasan_mem_to_shadow(row), META_BYTES_PER_ROW); } -#if CONFIG_KASAN_STACK +#if defined(CONFIG_KASAN_STACK) static bool __must_check tokenize_f
[PATCH] kasan: fix null pointer dereference in kasan_record_aux_stack
Syzbot reported the following [1]: BUG: kernel NULL pointer dereference, address: 0008 #PF: supervisor read access in kernel mode #PF: error_code(0x) - not-present page PGD 2d993067 P4D 2d993067 PUD 19a3c067 PMD 0 Oops: [#1] PREEMPT SMP KASAN CPU: 1 PID: 3852 Comm: kworker/1:2 Not tainted 5.10.0-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: events free_ipc RIP: 0010:kasan_record_aux_stack+0x77/0xb0 Add null checking slab object from kasan_get_alloc_meta() in order to avoid null pointer dereference. [1] https://syzkaller.appspot.com/x/log.txt?x=10a82a50d0 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin CC: Dmitry Vyukov CC: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrew Morton --- mm/kasan/generic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 1dd5a0f99372..5106b84b07d4 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -337,6 +337,8 @@ void kasan_record_aux_stack(void *addr) cache = page->slab_cache; object = nearest_obj(cache, page, addr); alloc_meta = kasan_get_alloc_meta(cache, object); + if (!alloc_meta) + return; alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0]; alloc_meta->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); -- 2.18.0
Re: BUG: unable to handle kernel NULL pointer dereference in call_rcu
On Sun, 2020-12-27 at 20:51 +0100, Dmitry Vyukov wrote: > /\/\/\/\On Sun, Dec 27, 2020 at 8:45 PM Andrew Morton > wrote: > > > > (cc KASAN developers) > > > > On Sat, 26 Dec 2020 15:25:14 -0800 syzbot > > wrote: > > > > > Hello, > > > > > > syzbot found the following issue on: > > > > > > HEAD commit:614cb589 Merge tag 'acpi-5.11-rc1-2' of > > > git://git.kernel.o.. > > > git tree: upstream > > > console output: https://syzkaller.appspot.com/x/log.txt?x=10a82a50d0 > > > kernel config: https://syzkaller.appspot.com/x/.config?x=bf519e1e96191576 > > > dashboard link: > > > https://syzkaller.appspot.com/bug?extid=9d3ede723bdc58553f13 > > > compiler: gcc (GCC) 10.1.0-syz 20200507 > > > syz repro: https://syzkaller.appspot.com/x/repro.syz?x=11830e9350 > > > C reproducer: https://syzkaller.appspot.com/x/repro.c?x=13d9205750 > > > > > > IMPORTANT: if you fix the issue, please add the following tag to the > > > commit: > > > Reported-by: syzbot+9d3ede723bdc58553...@syzkaller.appspotmail.com > > > > > > BUG: kernel NULL pointer dereference, address: 0008 > > > #PF: supervisor read access in kernel mode > > > #PF: error_code(0x) - not-present page > > > PGD 2d993067 P4D 2d993067 PUD 19a3c067 PMD 0 > > > Oops: [#1] PREEMPT SMP KASAN > > > CPU: 1 PID: 3852 Comm: kworker/1:2 Not tainted 5.10.0-syzkaller #0 > > > Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS > > > Google 01/01/2011 > > > Workqueue: events free_ipc > > > RIP: 0010:kasan_record_aux_stack+0x77/0xb0 mm/kasan/generic.c:341 > > +Walter, Andrey > > void kasan_record_aux_stack(void *addr) > { > ... > alloc_meta = kasan_get_alloc_meta(cache, object); > alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0]; > > /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ > It crashes on NULL deref here, I assume alloc_meta is NULL. We may not > have it for some slabs. Do we miss a NULL check here? > Hi Dmitry, Yes, I will send a patch to fix it. Thanks for your suggestion. Walter > > > > > > Code: 48 f7 fe 8b 47 24 49 89 f0 48 29 d3 8d 70 ff 41 0f af f0 48 01 ce > > > 48 39 f3 48 0f 46 f3 e8 81 e9 ff ff bf 00 08 00 00 48 89 c3 <8b> 40 08 89 > > > 43 0c e8 1e e6 ff ff 89 43 08 5b c3 48 8b 50 08 48 c7 > > > RSP: 0018:c90002e6fae8 EFLAGS: 00010046 > > > RAX: RBX: RCX: 88803980 > > > RDX: 0078 RSI: 88803980 RDI: 0800 > > > RBP: 837ef3a0 R08: 0040 R09: 002e > > > R10: 8132b7ea R11: 003f R12: 00035b40 > > > R13: 888039800088 R14: c90002e6fc08 R15: 0200 > > > FS: () GS:8880b9d0() > > > knlGS: > > > CS: 0010 DS: ES: CR0: 80050033 > > > CR2: 0008 CR3: 11841000 CR4: 001506e0 > > > DR0: DR1: DR2: > > > DR3: DR6: fffe0ff0 DR7: 0400 > > > Call Trace: > > > __call_rcu kernel/rcu/tree.c:2965 [inline] > > > call_rcu+0xbb/0x710 kernel/rcu/tree.c:3038 > > > ipc_rcu_putref+0x83/0xb0 ipc/util.c:505 > > > freeary+0x139c/0x1b30 ipc/sem.c:1188 > > > free_ipcs+0x98/0x1e0 ipc/namespace.c:112 > > > sem_exit_ns+0x1b/0x40 ipc/sem.c:260 > > > free_ipc_ns ipc/namespace.c:124 [inline] > > > free_ipc+0xf8/0x200 ipc/namespace.c:141 > > > process_one_work+0x98d/0x1630 kernel/workqueue.c:2275 > > > worker_thread+0x64c/0x1120 kernel/workqueue.c:2421 > > > kthread+0x3b1/0x4a0 kernel/kthread.c:292 > > > ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:296 > > > Modules linked in: > > > CR2: 0008 > > > ---[ end trace 28dc093e61d44dc2 ]--- > > > RIP: 0010:kasan_record_aux_stack+0x77/0xb0 mm/kasan/generic.c:341 > > > Code: 48 f7 fe 8b 47 24 49 89 f0 48 29 d3 8d 70 ff 41 0f af f0 48 01 ce > > > 48 39 f3 48 0f 46 f3 e8 81 e9 ff ff bf 00 08 00 00 48 89 c3 <8b> 40 08 89 > > > 43 0c e8 1e e6 ff ff 89 43 08 5b c3 48 8b 50 08 48 c7 > > > RSP: 0018:c90002e6fae8 EFLAGS: 00010046 > > > RAX: RBX: RCX: 88803980 > > > RDX: 0078 RSI: 88803980 RDI: 0800 > > > RBP: 837ef3a0 R08: 0040 R09: 002e > > > R10: 8132b7ea R11: 003f R12: 00035b40 > > > R13: 888039800088 R14: c90002e6fc08 R15: 0200 > > > FS: () GS:8880b9d0() > > > knlGS: > > > CS: 0010 DS: ES: CR0: 80050033 > > > CR2: 0008 CR3: 11841000 CR4: 001506e0 > > > DR0: DR1: DR2: > > > DR3: DR6: fffe0ff0 DR7: 0400 > > > > > > > > > --- > > > This report is generated by a bot. It may contain errors. > > > See https://goo.gl/tpsmEJ for more information about syzbot. > > > syzbot
Re: [PATCH v5 3/4] lib/test_kasan.c: add workqueue test case
On Thu, 2020-12-03 at 11:29 +0100, Marco Elver wrote: > On Thu, 3 Dec 2020 at 03:27, Walter Wu wrote: > > > > Adds a test to verify workqueue stack recording and print it in > > KASAN report. > > > > The KASAN report was as follows(cleaned up slightly): > > > > BUG: KASAN: use-after-free in kasan_workqueue_uaf > > > > Freed by task 54: > > kasan_save_stack+0x24/0x50 > > kasan_set_track+0x24/0x38 > > kasan_set_free_info+0x20/0x40 > > __kasan_slab_free+0x10c/0x170 > > kasan_slab_free+0x10/0x18 > > kfree+0x98/0x270 > > kasan_workqueue_work+0xc/0x18 > > > > Last potentially related work creation: > > kasan_save_stack+0x24/0x50 > > kasan_record_wq_stack+0xa8/0xb8 > > insert_work+0x48/0x288 > > __queue_work+0x3e8/0xc40 > > queue_work_on+0xf4/0x118 > > kasan_workqueue_uaf+0xfc/0x190 > > > > Signed-off-by: Walter Wu > > Acked-by: Marco Elver > > Reviewed-by: Dmitry Vyukov > > Reviewed-by: Andrey Konovalov > > Cc: Andrey Ryabinin > > Cc: Alexander Potapenko > > Cc: Matthias Brugger > > --- > > > > v4: > > - testcase has merge conflict, so that rebase onto the KASAN-KUNIT > > > > --- > > lib/test_kasan_module.c | 29 + > > 1 file changed, 29 insertions(+) > > > > diff --git a/lib/test_kasan_module.c b/lib/test_kasan_module.c > > index 2d68db6ae67b..62a87854b120 100644 > > --- a/lib/test_kasan_module.c > > +++ b/lib/test_kasan_module.c > > @@ -91,6 +91,34 @@ static noinline void __init kasan_rcu_uaf(void) > > call_rcu(_rcu_ptr->rcu, kasan_rcu_reclaim); > > } > > > > +static noinline void __init kasan_workqueue_work(struct work_struct *work) > > +{ > > + kfree(work); > > +} > > + > > +static noinline void __init kasan_workqueue_uaf(void) > > +{ > > + struct workqueue_struct *workqueue; > > + struct work_struct *work; > > + > > + workqueue = create_workqueue("kasan_wq_test"); > > + if (!workqueue) { > > + pr_err("Allocation failed\n"); > > + return; > > + } > > + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); > > + if (!work) { > > + pr_err("Allocation failed\n"); > > + return; > > + } > > + > > + INIT_WORK(work, kasan_workqueue_work); > > + queue_work(workqueue, work); > > + destroy_workqueue(workqueue); > > + > > + pr_info("use-after-free on workqueue\n"); > > + ((volatile struct work_struct *)work)->data; > > +} > > > > static int __init test_kasan_module_init(void) > > { > > @@ -102,6 +130,7 @@ static int __init test_kasan_module_init(void) > > > > copy_user_test(); > > kasan_rcu_uaf(); > > + kasan_workqueue_uaf(); > > > Why can't this go into the KUnit based KASAN test? This test case has not been ported to KUnit, because KUnit's expect failure will not check whether the work stack is exist. So it remains in test_kasan_module, it is the same with kasan_rcu_uaf()[1]. [1]https://lkml.org/lkml/2020/8/1/45 Thanks. Walter
[PATCH v5 4/4] kasan: update documentation for generic kasan
Generic KASAN also supports to record the last two workqueue stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Jonathan Corbet --- v4: - remove timer stack description v3: - Thanks for Marco suggestion --- Documentation/dev-tools/kasan.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c09c9ca2ff1c..3cb556ceb4a5 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -190,8 +190,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. -Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one -and the second to last. +Generic KASAN also reports the last 2 call stacks to creation of work that +potentially has access to an object. Call stacks for the following are shown: +call_rcu() and workqueue queuing. Software tag-based KASAN -- 2.18.0
[PATCH v5 3/4] lib/test_kasan.c: add workqueue test case
Adds a test to verify workqueue stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_workqueue_uaf Freed by task 54: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_workqueue_work+0xc/0x18 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_wq_stack+0xa8/0xb8 insert_work+0x48/0x288 __queue_work+0x3e8/0xc40 queue_work_on+0xf4/0x118 kasan_workqueue_uaf+0xfc/0x190 Signed-off-by: Walter Wu Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger --- v4: - testcase has merge conflict, so that rebase onto the KASAN-KUNIT --- lib/test_kasan_module.c | 29 + 1 file changed, 29 insertions(+) diff --git a/lib/test_kasan_module.c b/lib/test_kasan_module.c index 2d68db6ae67b..62a87854b120 100644 --- a/lib/test_kasan_module.c +++ b/lib/test_kasan_module.c @@ -91,6 +91,34 @@ static noinline void __init kasan_rcu_uaf(void) call_rcu(_rcu_ptr->rcu, kasan_rcu_reclaim); } +static noinline void __init kasan_workqueue_work(struct work_struct *work) +{ + kfree(work); +} + +static noinline void __init kasan_workqueue_uaf(void) +{ + struct workqueue_struct *workqueue; + struct work_struct *work; + + workqueue = create_workqueue("kasan_wq_test"); + if (!workqueue) { + pr_err("Allocation failed\n"); + return; + } + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + pr_err("Allocation failed\n"); + return; + } + + INIT_WORK(work, kasan_workqueue_work); + queue_work(workqueue, work); + destroy_workqueue(workqueue); + + pr_info("use-after-free on workqueue\n"); + ((volatile struct work_struct *)work)->data; +} static int __init test_kasan_module_init(void) { @@ -102,6 +130,7 @@ static int __init test_kasan_module_init(void) copy_user_test(); kasan_rcu_uaf(); + kasan_workqueue_uaf(); kasan_restore_multi_shot(multishot); return -EAGAIN; -- 2.18.0
[PATCH v5 2/4] kasan: print workqueue stack
The aux_stack[2] is reused to record the call_rcu() call stack and enqueuing work call stacks. So that we need to change the auxiliary stack title for common title, print them in KASAN report. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko --- v4: - remove a mention of call_rcu() at kasan_record_aux_stack() Thanks for Alexander reminder. v2: - Thanks for Marco suggestion. - We modify aux stack title name in KASAN report in order to print call_rcu()/timer/workqueue stack. --- mm/kasan/generic.c | 3 --- mm/kasan/report.c | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 248264b9cb76..30c0a5038b5c 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -339,9 +339,6 @@ void kasan_record_aux_stack(void *addr) object = nearest_obj(cache, page, addr); alloc_info = get_alloc_info(cache, object); - /* -* record the last two call_rcu() call stacks. -*/ alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 00a53f1355ae..5a0102f37171 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -185,12 +185,12 @@ static void describe_object(struct kmem_cache *cache, void *object, #ifdef CONFIG_KASAN_GENERIC if (alloc_info->aux_stack[0]) { - pr_err("Last call_rcu():\n"); + pr_err("Last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[0]); pr_err("\n"); } if (alloc_info->aux_stack[1]) { - pr_err("Second to last call_rcu():\n"); + pr_err("Second to last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[1]); pr_err("\n"); } -- 2.18.0
[PATCH v5 1/4] workqueue: kasan: record workqueue stack
When analyze use-after-free or double-free issue, recording the enqueuing work stacks is helpful to preserve usage history which potentially gives a hint about the affected code. For workqueue it has turned out to be useful to record the enqueuing work call stacks. Because user can see KASAN report to determine whether it is root cause. They don't need to enable debugobjects, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Acked-by: Tejun Heo Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Lai Jiangshan --- v2: - Thanks for Marco suggestion. - Remove unnecessary code - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack --- kernel/workqueue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c41c3c17b86a..9dd65ac60d6e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1324,6 +1324,9 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, { struct worker_pool *pool = pwq->pool; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(>entry, head); -- 2.18.0
[PATCH v5 0/4] kasan: add workqueue stack for generic KASAN
Syzbot reports many UAF issues for workqueue, see [1]. In some of these access/allocation happened in process_one_work(), we see the free stack is useless in KASAN report, it doesn't help programmers to solve UAF for workqueue issue. This patchset improves KASAN reports by making them to have workqueue queueing stack. It is useful for programmers to solve use-after-free or double-free memory issue. Generic KASAN also records the last two workqueue stacks and prints them in KASAN report. It is only suitable for generic KASAN. [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work [2]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Walter Wu (4): workqueue: kasan: record workqueue stack kasan: print workqueue stack lib/test_kasan.c: add workqueue test case kasan: update documentation for generic kasan --- Changes since v4: - Not found timer use case, so that remove timer patch - remove a mention of call_rcu() from the kasan_record_aux_stack() Thanks for Dmitry and Alexander suggestion. Changes since v3: - testcases have merge conflict, so that need to be rebased onto the KASAN-KUNIT. Changes since v2: - modify kasan document to be readable, Thanks for Marco suggestion. Changes since v1: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. - change the aux stack title for common name. --- Documentation/dev-tools/kasan.rst | 5 +++-- kernel/workqueue.c| 3 +++ lib/test_kasan_module.c | 29 + mm/kasan/generic.c| 4 +--- mm/kasan/report.c | 4 ++-- 5 files changed, 38 insertions(+), 7 deletions(-)
Re: [PATCH v4 0/6] kasan: add workqueue and timer stack for generic KASAN
On Tue, 2020-12-01 at 15:02 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > On Tue, Dec 1, 2020 at 12:17 PM Walter Wu wrote: > > > > Hi Dmitry, > > > > On Tue, 2020-12-01 at 08:59 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > > > On Wed, Sep 30, 2020 at 5:29 PM Thomas Gleixner > > > wrote: > > > > > > > > On Thu, Sep 24 2020 at 12:01, Walter Wu wrote: > > > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and > > > > > [2]. > > > > > In some of these access/allocation happened in process_one_work(), > > > > > we see the free stack is useless in KASAN report, it doesn't help > > > > > programmers to solve UAF on workqueue. The same may stand for times. > > > > > > > > > > This patchset improves KASAN reports by making them to have workqueue > > > > > queueing stack and timer stack information. It is useful for > > > > > programmers > > > > > to solve use-after-free or double-free memory issue. > > > > > > > > > > Generic KASAN also records the last two workqueue and timer stacks and > > > > > prints them in KASAN report. It is only suitable for generic KASAN. > > > > > > Walter, did you mail v5? > > > Checking statuses of KASAN issues and this seems to be not in linux-next. > > > > > > > Sorry for the delay in responding to this patch. I'm busy these few > > months, so that suspend processing it. > > Yes, I will send it next week. But v4 need to confirm the timer stack is > > useful. I haven't found an example. Do you have some suggestion about > > timer? > > Good question. > > We had some use-after-free's what mention call_timer_fn: > https://groups.google.com/g/syzkaller-bugs/search?q=%22kasan%22%20%22use-after-free%22%20%22expire_timers%22%20%22call_timer_fn%22%20 > In the reports I checked call_timer_fn appears in the "access" stack > rather in the "free" stack. > Yes, call stack already is useful for it in KASAN report. > Looking at these reports I cannot conclude that do_init_timer stack > would be useful. > I am mildly leaning towards not memorizing do_init_timer stack for now > (until we have clear use cases) as the number of aux stacks is very > limited (2). > Got it. I will remove timer patch and send v5. Thanks for your suggestion. Walter
Re: [PATCH v4 0/6] kasan: add workqueue and timer stack for generic KASAN
Hi Dmitry, On Tue, 2020-12-01 at 08:59 +0100, 'Dmitry Vyukov' via kasan-dev wrote: > On Wed, Sep 30, 2020 at 5:29 PM Thomas Gleixner wrote: > > > > On Thu, Sep 24 2020 at 12:01, Walter Wu wrote: > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. > > > In some of these access/allocation happened in process_one_work(), > > > we see the free stack is useless in KASAN report, it doesn't help > > > programmers to solve UAF on workqueue. The same may stand for times. > > > > > > This patchset improves KASAN reports by making them to have workqueue > > > queueing stack and timer stack information. It is useful for programmers > > > to solve use-after-free or double-free memory issue. > > > > > > Generic KASAN also records the last two workqueue and timer stacks and > > > prints them in KASAN report. It is only suitable for generic KASAN. > > Walter, did you mail v5? > Checking statuses of KASAN issues and this seems to be not in linux-next. > Sorry for the delay in responding to this patch. I'm busy these few months, so that suspend processing it. Yes, I will send it next week. But v4 need to confirm the timer stack is useful. I haven't found an example. Do you have some suggestion about timer? Thanks. Walter > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work > > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers > > > > How are these links useful for people who do not have a gurgle account? > > This is a public mailing list archive, so effectively the same way as > lore links ;) >
Re: [PATCH v4 1/6] timer: kasan: record timer stack
Hi Thomas, On Sat, 2020-09-26 at 00:59 +0200, Thomas Gleixner wrote: > On Fri, Sep 25 2020 at 17:15, Walter Wu wrote: > > On Fri, 2020-09-25 at 10:55 +0200, Thomas Gleixner wrote: > >> > We don't want to replace DEBUG_OBJECTS_TIMERS with this patches, only > >> > hope to use low overhead(compare with DEBUG_OBJECTS_TIMERS) to debug > >> > >> KASAN has lower overhead than DEBUG_OBJECTS_TIMERS? Maybe in a different > >> universe. > >> > > I mean KASAN + our patch vs KASAN + DEBUG_OBJECTS_TIMERS. The front one > > have the information to the original caller and help to debug. It is > > smaller overhead than the one behind. > > For ONE specific problem related to timers and you have still not shown > a single useful debug output where this information helps to debug > anything. > > > I agree your saying, so that I need to find out a use case to explain to > > you. > > Indeed. > First, I think the commit log “Because if the UAF root cause is in timer init …” needs to be removed, this patch hopes to help programmer gets timer callback is where is registered. It is useful only if free stack is called from timer callback, because programmer can see why & where register this function. Second, see [1], it should satisfies first point. The free stack is from timer callback, if we know where register this function, then it should be useful to solve UAF. [1]https://lore.kernel.org/linux-usb/590f6b05a1c05...@google.com/ Thanks Walter > Thanks, > > tglx >
Re: [PATCH v4 1/6] timer: kasan: record timer stack
On Fri, 2020-09-25 at 10:55 +0200, Thomas Gleixner wrote: > Walter, > > On Fri, Sep 25 2020 at 15:18, Walter Wu wrote: > > On Thu, 2020-09-24 at 23:41 +0200, Thomas Gleixner wrote: > >> > For timers it has turned out to be useful to record the stack trace > >> > of the timer init call. > >> > >> In which way? And what kind of bug does it catch which cannot be catched > >> by existing debug mechanisms already? > >> > > We only provide another debug mechanisms to debug use-after-free or > > double-free, it can be displayed together in KASAN report and have a > > chance to debug, and it doesn't need to enable existing debug mechanisms > > at the same time. then it has a chance to resolve issue. > > Again. KASAN can only cover UAF, but there are a dozen other ways to > wreck the system with wrong usage of timers which can't be caught by > KASAN. > > >> > Because if the UAF root cause is in timer init, then user can see > >> > KASAN report to get where it is registered and find out the root > >> > cause. > >> > >> What? If the UAF root cause is in timer init, then registering it after > >> using it in that very same function is pretty pointless. > >> > > See [1], the call stack shows UAF happen at dummy_timer(), it is the > > callback function and set by timer_setup(), if KASAN report shows the > > timer call stack, it should be useful for programmer. > > The report you linked to has absolutely nothing to do with a timer > related UAF. The timer callback calls kfree_skb() on something which is > already freed. So the root cause of this is NOT in timer init as you > claimed above. The timer callback is just exposing a problem in the URB > management of this driver. IOW the recording of the timer init stack is > completely useless for decoding this problem. > > >> There is a lot of handwaving how useful this is, but TBH I don't see the > >> value at all. > >> > >> DEBUG_OBJECTS_TIMERS does a lot more than crashing on UAF. If KASAN > >> provides additional value over DEBUG_OBJECTS_TIMERS then spell it out, > >> but just saying that you don't need to enable DEBUG_OBJECTS_TIMERS is > >> not making an argument for that change. > >> > > We don't want to replace DEBUG_OBJECTS_TIMERS with this patches, only > > hope to use low overhead(compare with DEBUG_OBJECTS_TIMERS) to debug > > KASAN has lower overhead than DEBUG_OBJECTS_TIMERS? Maybe in a different > universe. > I mean KASAN + our patch vs KASAN + DEBUG_OBJECTS_TIMERS. The front one have the information to the original caller and help to debug. It is smaller overhead than the one behind. > That said, I'm not opposed to the change per se, but without a sensible > justification this is just pointless. > > Sprinkling kasan_foo() all over the place and claiming it's useful > without a valid example does not provide any value. > > Quite the contrary it gives the completely wrong sense what KASAN can do > and what not. > I agree your saying, so that I need to find out a use case to explain to you. Thanks Walter > Thanks, > > tglx >
Re: [PATCH v4 1/6] timer: kasan: record timer stack
On Thu, 2020-09-24 at 23:41 +0200, Thomas Gleixner wrote: > On Thu, Sep 24 2020 at 12:03, Walter Wu wrote: > > When analyze use-after-free or double-free issue, recording the timer > > stacks is helpful to preserve usage history which potentially gives > > a hint about the affected code. > > > > Record the most recent two timer init calls in KASAN which are printed > > on failure in the KASAN report. > > > > For timers it has turned out to be useful to record the stack trace > > of the timer init call. > > In which way? And what kind of bug does it catch which cannot be catched > by existing debug mechanisms already? > We only provide another debug mechanisms to debug use-after-free or double-free, it can be displayed together in KASAN report and have a chance to debug, and it doesn't need to enable existing debug mechanisms at the same time. then it has a chance to resolve issue. > > Because if the UAF root cause is in timer init, then user can see > > KASAN report to get where it is registered and find out the root > > cause. > > What? If the UAF root cause is in timer init, then registering it after > using it in that very same function is pretty pointless. > See [1], the call stack shows UAF happen at dummy_timer(), it is the callback function and set by timer_setup(), if KASAN report shows the timer call stack, it should be useful for programmer. [1] https://syzkaller.appspot.com/bug?id=34e69b7c8c0165658cbc987da0b61dadec644b6b > > It don't need to enable DEBUG_OBJECTS_TIMERS, but they have a chance > > to find out the root cause. > > There is a lot of handwaving how useful this is, but TBH I don't see the > value at all. > > DEBUG_OBJECTS_TIMERS does a lot more than crashing on UAF. If KASAN > provides additional value over DEBUG_OBJECTS_TIMERS then spell it out, > but just saying that you don't need to enable DEBUG_OBJECTS_TIMERS is > not making an argument for that change. > We don't want to replace DEBUG_OBJECTS_TIMERS with this patches, only hope to use low overhead(compare with DEBUG_OBJECTS_TIMERS) to debug use-after-free/double-free issue. If you have some concerns, we can add those message into commit log. Thanks. Walter
Re: [PATCH v4 0/6] kasan: add workqueue and timer stack for generic KASAN
On Thu, 2020-09-24 at 13:51 +0200, 'Alexander Potapenko' via kasan-dev wrote: > > --- > > Documentation/dev-tools/kasan.rst | 5 +++-- > > kernel/time/timer.c | 3 +++ > > kernel/workqueue.c| 3 +++ > > lib/test_kasan_module.c | 55 > > +++ > > mm/kasan/report.c | 4 ++-- > > 5 files changed, 66 insertions(+), 4 deletions(-) > > While at it, can you remove a mention of call_rcu() from the > kasan_record_aux_stack() implementation, as it is no more > RCU-specific? > Thank you for your reminder. v5 will do it. Walter
[PATCH v4 6/6] kasan: update documentation for generic kasan
Generic KASAN also supports to record the last two timer and workqueue stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Jonathan Corbet --- v3: - Thanks for Marco suggestion --- Documentation/dev-tools/kasan.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index 38fd5681fade..698ccb65e634 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -190,8 +190,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. -Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one -and the second to last. +Generic KASAN also reports the last 2 call stacks to creation of work that +potentially has access to an object. Call stacks for the following are shown: +call_rcu(), timer and workqueue queuing. Software tag-based KASAN -- 2.18.0
[PATCH v4 3/6] kasan: print timer and workqueue stack
The aux_stack[2] is reused to record the call_rcu() call stack, timer init call stack, and enqueuing work call stacks. So that we need to change the auxiliary stack title for common title, print them in KASAN report. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko --- v2: - Thanks for Marco suggestion. - We modify aux stack title name in KASAN report in order to print call_rcu()/timer/workqueue stack. --- mm/kasan/report.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 4f49fa6cd1aa..886809d0a8dd 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -183,12 +183,12 @@ static void describe_object(struct kmem_cache *cache, void *object, #ifdef CONFIG_KASAN_GENERIC if (alloc_info->aux_stack[0]) { - pr_err("Last call_rcu():\n"); + pr_err("Last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[0]); pr_err("\n"); } if (alloc_info->aux_stack[1]) { - pr_err("Second to last call_rcu():\n"); + pr_err("Second to last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[1]); pr_err("\n"); } -- 2.18.0
[PATCH v4 2/6] workqueue: kasan: record workqueue stack
Records the last two enqueuing work call stacks in order to print them in KASAN report. It is useful for programmers to solve use-after-free or double-free memory workqueue issue. For workqueue it has turned out to be useful to record the enqueuing work call stacks. Because user can see KASAN report to determine whether it is root cause. They don't need to enable debugobjects, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Acked-by: Marco Elver Acked-by: Tejun Heo Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Lai Jiangshan --- v2: - Thanks for Marco suggestion. - Remove unnecessary code - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack --- kernel/workqueue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c41c3c17b86a..5fea7dc9180f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1324,6 +1324,9 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, { struct worker_pool *pool = pwq->pool; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(>entry, head); -- 2.18.0
[PATCH v4 1/6] timer: kasan: record timer stack
When analyze use-after-free or double-free issue, recording the timer stacks is helpful to preserve usage history which potentially gives a hint about the affected code. Record the most recent two timer init calls in KASAN which are printed on failure in the KASAN report. For timers it has turned out to be useful to record the stack trace of the timer init call. Because if the UAF root cause is in timer init, then user can see KASAN report to get where it is registered and find out the root cause. It don't need to enable DEBUG_OBJECTS_TIMERS, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Suggested-by: Thomas Gleixner Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd --- v2: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. --- kernel/time/timer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index a16764b0116e..1ed8f8aca7f5 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -796,6 +796,9 @@ static void do_init_timer(struct timer_list *timer, timer->function = func; timer->flags = flags | raw_smp_processor_id(); lockdep_init_map(>lockdep_map, name, key, 0); + + /* record the timer stack in order to print it in KASAN report */ + kasan_record_aux_stack(timer); } /** -- 2.18.0
PATCH v4 5/6] kasan: add tests for workqueue stack recording
Adds a test to verify workqueue stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_workqueue_uaf Freed by task 54: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_workqueue_work+0xc/0x18 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_wq_stack+0xa8/0xb8 insert_work+0x48/0x288 __queue_work+0x3e8/0xc40 queue_work_on+0xf4/0x118 kasan_workqueue_uaf+0xfc/0x190 Signed-off-by: Walter Wu Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger --- v4: - testcase has merge conflict, so that rebase onto the KASAN-KUNIT --- lib/test_kasan_module.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan_module.c b/lib/test_kasan_module.c index 2e5e7be96955..c3a2d113e757 100644 --- a/lib/test_kasan_module.c +++ b/lib/test_kasan_module.c @@ -115,6 +115,35 @@ static noinline void __init kasan_timer_uaf(void) ((volatile struct timer_list *)timer)->expires; } +static noinline void __init kasan_workqueue_work(struct work_struct *work) +{ + kfree(work); +} + +static noinline void __init kasan_workqueue_uaf(void) +{ + struct workqueue_struct *workqueue; + struct work_struct *work; + + workqueue = create_workqueue("kasan_wq_test"); + if (!workqueue) { + pr_err("Allocation failed\n"); + return; + } + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + pr_err("Allocation failed\n"); + return; + } + + INIT_WORK(work, kasan_workqueue_work); + queue_work(workqueue, work); + destroy_workqueue(workqueue); + + pr_info("use-after-free on workqueue\n"); + ((volatile struct work_struct *)work)->data; +} + static int __init test_kasan_module_init(void) { /* @@ -126,6 +155,7 @@ static int __init test_kasan_module_init(void) copy_user_test(); kasan_rcu_uaf(); kasan_timer_uaf(); + kasan_workqueue_uaf(); kasan_restore_multi_shot(multishot); return -EAGAIN; -- 2.18.0
[PATCH v4 4/6] kasan: add tests for timer stack recording
Adds a test to verify timer stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_timer_uaf Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_timer_function+0x1c/0x28 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_tmr_stack+0xa8/0xb8 init_timer_key+0xf0/0x248 kasan_timer_uaf+0x5c/0xd8 Signed-off-by: Walter Wu Acked-by: Marco Elver Reviewed-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger --- v4: - testcase has merge conflict, so that rebase onto the KASAN-KUNIT --- lib/test_kasan_module.c | 25 + 1 file changed, 25 insertions(+) diff --git a/lib/test_kasan_module.c b/lib/test_kasan_module.c index 2d68db6ae67b..d8234a1db8c9 100644 --- a/lib/test_kasan_module.c +++ b/lib/test_kasan_module.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "../mm/kasan/kasan.h" @@ -91,6 +92,29 @@ static noinline void __init kasan_rcu_uaf(void) call_rcu(_rcu_ptr->rcu, kasan_rcu_reclaim); } +static noinline void __init kasan_timer_function(struct timer_list *timer) +{ + del_timer(timer); + kfree(timer); +} + +static noinline void __init kasan_timer_uaf(void) +{ + struct timer_list *timer; + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) { + pr_err("Allocation failed\n"); + return; + } + + timer_setup(timer, kasan_timer_function, 0); + add_timer(timer); + msleep(100); + + pr_info("use-after-free on timer\n"); + ((volatile struct timer_list *)timer)->expires; +} static int __init test_kasan_module_init(void) { @@ -102,6 +126,7 @@ static int __init test_kasan_module_init(void) copy_user_test(); kasan_rcu_uaf(); + kasan_timer_uaf(); kasan_restore_multi_shot(multishot); return -EAGAIN; -- 2.18.0
[PATCH v4 0/6] kasan: add workqueue and timer stack for generic KASAN
Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. In some of these access/allocation happened in process_one_work(), we see the free stack is useless in KASAN report, it doesn't help programmers to solve UAF on workqueue. The same may stand for times. This patchset improves KASAN reports by making them to have workqueue queueing stack and timer stack information. It is useful for programmers to solve use-after-free or double-free memory issue. Generic KASAN also records the last two workqueue and timer stacks and prints them in KASAN report. It is only suitable for generic KASAN. [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Walter Wu (6): timer: kasan: record timer stack workqueue: kasan: record workqueue stack kasan: print timer and workqueue stack lib/test_kasan.c: add timer test case lib/test_kasan.c: add workqueue test case kasan: update documentation for generic kasan --- Changes since v3: - testcases have merge conflict, so that need to be rebased onto the KASAN-KUNIT. Changes since v2: - modify kasan document to be readable, Thanks for Marco suggestion. Changes since v1: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. - change the aux stack title for common name. --- Documentation/dev-tools/kasan.rst | 5 +++-- kernel/time/timer.c | 3 +++ kernel/workqueue.c| 3 +++ lib/test_kasan_module.c | 55 +++ mm/kasan/report.c | 4 ++-- 5 files changed, 66 insertions(+), 4 deletions(-)
Re: [PATCH v3 0/6] kasan: add workqueue and timer stack for generic KASAN
On Mon, 2020-09-14 at 14:25 +0200, Andrey Konovalov wrote: > On Sun, Sep 13, 2020 at 12:17 PM Dmitry Vyukov > wrote: > > On Wed, Aug 26, 2020 at 2:30 PM 'Andrey Konovalov' via > kasan-dev > wrote: > > > > On Tue, Aug 25, 2020 at 10:26 AM 'Marco Elver' via kasan-dev > > wrote: > > > > > > On Tue, 25 Aug 2020 at 03:57, Walter Wu > wrote: > > > > > > > > Syzbot reports many UAF issues for workqueue or timer, > see [1] and [2]. > > > > In some of these access/allocation happened in > process_one_work(), > > > > we see the free stack is useless in KASAN report, it > doesn't help > > > > programmers to solve UAF on workqueue. The same may > stand for times. > > > > > > > > This patchset improves KASAN reports by making them to > have workqueue > > > > queueing stack and timer stack information. It is useful > for programmers > > > > to solve use-after-free or double-free memory issue. > > > > > > > > Generic KASAN also records the last two workqueue and > timer stacks and > > > > prints them in KASAN report. It is only suitable for > generic KASAN. > > > > > > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=% > 22use-after-free%22+process_one_work > > > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=% > 22use-after-free%22%20expire_timers > > > > [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > Walter Wu (6): > > > > timer: kasan: record timer stack > > > > workqueue: kasan: record workqueue stack > > > > kasan: print timer and workqueue stack > > > > lib/test_kasan.c: add timer test case > > > > lib/test_kasan.c: add workqueue test case > > > > kasan: update documentation for generic kasan > > > > > > Acked-by: Marco Elver > > > > Reviewed-by: Andrey Konovalov > > Reviewed-by: Dmitry Vyukov > > Thanks! The UAF reports with RCU stacks that I see now are > just > > > Hi Walter, > > > This patchset needs to be rebased onto the KASAN-KUNIT patches, which > just recently went into the mm tree. > > > Thanks! Hi Dmitry, Andrey, Got it. Thanks for your review and reminder. Walter
Re: [PATCH v2 0/6] kasan: add workqueue and timer stack for generic KASAN
On Mon, 2020-08-24 at 13:50 +0200, Marco Elver wrote: > On Mon, 24 Aug 2020 at 10:07, Walter Wu wrote: > > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. > > In some of these access/allocation happened in process_one_work(), > > we see the free stack is useless in KASAN report, it doesn't help > > programmers to solve UAF on workqueue. The same may stand for times. > > > > This patchset improves KASAN reports by making them to have workqueue > > queueing stack and timer queueing stack information. It is useful for > > programmers to solve use-after-free or double-free memory issue. > > > > Generic KASAN will record the last two workqueue and timer stacks, > > print them in KASAN report. It is only suitable for generic KASAN. > > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers > > [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > Walter Wu (6): > > timer: kasan: record timer stack > > workqueue: kasan: record workqueue stack > > kasan: print timer and workqueue stack > > lib/test_kasan.c: add timer test case > > lib/test_kasan.c: add workqueue test case > > kasan: update documentation for generic kasan > > > > --- > > > > Changes since v1: > > - Thanks for Marco and Thomas suggestion. > > - Remove unnecessary code and fix commit log > > - reuse kasan_record_aux_stack() and aux_stack > > to record timer and workqueue stack. > > - change the aux stack title for common name. > > Much cleaner. > > In general, > > Acked-by: Marco Elver > > but I left some more comments. I'm a bit worried about the tests, > because of KASAN-test KUnit rework, but probably not much we can do > until these are added to -mm tree. > Hi Marco, Thanks for your review and friendly reminder. If needed, I will rebase and resend the test case. Walter > Thanks, > -- Marco
[PATCH v3 6/6] kasan: update documentation for generic kasan
Generic KASAN also supports to record the last two timer and workqueue stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Suggested-by: Marco Elver Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- v3: - Thanks for Macro suggestion --- Documentation/dev-tools/kasan.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index 38fd5681fade..698ccb65e634 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -190,8 +190,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. -Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one -and the second to last. +Generic KASAN also reports the last 2 call stacks to creation of work that +potentially has access to an object. Call stacks for the following are shown: +call_rcu(), timer and workqueue queuing. Software tag-based KASAN -- 2.18.0
[PATCH v3 5/6] kasan: add tests for workqueue stack recording
Adds a test to verify workqueue stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_workqueue_uaf Freed by task 54: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_workqueue_work+0xc/0x18 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_wq_stack+0xa8/0xb8 insert_work+0x48/0x288 __queue_work+0x3e8/0xc40 queue_work_on+0xf4/0x118 kasan_workqueue_uaf+0xfc/0x190 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov --- lib/test_kasan.c | 29 + 1 file changed, 29 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 2bd61674c7a3..7293a55ff51c 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -845,6 +845,34 @@ static noinline void __init kasan_timer_uaf(void) ((volatile struct timer_list *)timer)->expires; } +static noinline void __init kasan_workqueue_work(struct work_struct *work) +{ + kfree(work); +} + +static noinline void __init kasan_workqueue_uaf(void) +{ + struct workqueue_struct *workqueue; + struct work_struct *work; + + workqueue = create_workqueue("kasan_wq_test"); + if (!workqueue) { + pr_err("Allocation failed\n"); + return; + } + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + pr_err("Allocation failed\n"); + return; + } + + INIT_WORK(work, kasan_workqueue_work); + queue_work(workqueue, work); + destroy_workqueue(workqueue); + + pr_info("use-after-free on workqueue\n"); + ((volatile struct work_struct *)work)->data; +} static int __init kmalloc_tests_init(void) { /* @@ -894,6 +922,7 @@ static int __init kmalloc_tests_init(void) vmalloc_oob(); kasan_rcu_uaf(); kasan_timer_uaf(); + kasan_workqueue_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v3 4/6] kasan: add tests for timer stack recording
Adds a test to verify timer stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_timer_uaf Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_timer_function+0x1c/0x28 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_tmr_stack+0xa8/0xb8 init_timer_key+0xf0/0x248 kasan_timer_uaf+0x5c/0xd8 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov --- lib/test_kasan.c | 25 + 1 file changed, 25 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 6e5fb05d42d8..2bd61674c7a3 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -821,6 +821,30 @@ static noinline void __init kasan_rcu_uaf(void) call_rcu(_ptr->rcu, kasan_rcu_reclaim); } +static noinline void __init kasan_timer_function(struct timer_list *timer) +{ + del_timer(timer); + kfree(timer); +} + +static noinline void __init kasan_timer_uaf(void) +{ + struct timer_list *timer; + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) { + pr_err("Allocation failed\n"); + return; + } + + timer_setup(timer, kasan_timer_function, 0); + add_timer(timer); + msleep(100); + + pr_info("use-after-free on timer\n"); + ((volatile struct timer_list *)timer)->expires; +} + static int __init kmalloc_tests_init(void) { /* @@ -869,6 +893,7 @@ static int __init kmalloc_tests_init(void) kmalloc_double_kzfree(); vmalloc_oob(); kasan_rcu_uaf(); + kasan_timer_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v3 3/6] kasan: print timer and workqueue stack
The aux_stack[2] is reused to record the call_rcu() call stack, timer init call stack, and enqueuing work call stacks. So that we need to change the auxiliary stack title for common title, print them in KASAN report. Signed-off-by: Walter Wu Suggested-by: Marco Elver Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko --- v2: - Thanks for Marco suggestion. - We modify aux stack title name in KASAN report in order to print call_rcu()/timer/workqueue stack. --- mm/kasan/report.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 4f49fa6cd1aa..886809d0a8dd 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -183,12 +183,12 @@ static void describe_object(struct kmem_cache *cache, void *object, #ifdef CONFIG_KASAN_GENERIC if (alloc_info->aux_stack[0]) { - pr_err("Last call_rcu():\n"); + pr_err("Last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[0]); pr_err("\n"); } if (alloc_info->aux_stack[1]) { - pr_err("Second to last call_rcu():\n"); + pr_err("Second to last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[1]); pr_err("\n"); } -- 2.18.0
[PATCH v3 1/6] timer: kasan: record timer stack
When analyze use-after-free or double-free issue, recording the timer stacks is helpful to to preserve usage history which potentially gives a hint about the affected code. Record the most recent two timer init calls in KASAN which are printed on failure in the KASAN report. For timers it has turned out to be useful to record the stack trace of the timer init call. Because if the UAF root cause is in timer init, then user can see KASAN report to get where it is registered and find out the root cause. It don't need to enable DEBUG_OBJECTS_TIMERS, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Suggested-by: Thomas Gleixner Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd --- v2: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. --- kernel/time/timer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index a16764b0116e..1ed8f8aca7f5 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -796,6 +796,9 @@ static void do_init_timer(struct timer_list *timer, timer->function = func; timer->flags = flags | raw_smp_processor_id(); lockdep_init_map(>lockdep_map, name, key, 0); + + /* record the timer stack in order to print it in KASAN report */ + kasan_record_aux_stack(timer); } /** -- 2.18.0
[PATCH v3 2/6] workqueue: kasan: record workqueue stack
Records the last two enqueuing work call stacks in order to print them in KASAN report. It is useful for programmers to solve use-after-free or double-free memory workqueue issue. For workqueue it has turned out to be useful to record the enqueuing work call stacks. Because user can see KASAN report to determine whether it is root cause. They don't need to enable debugobjects, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Tejun Heo Cc: Lai Jiangshan --- v2: - Thanks for Marco suggestion. - Remove unnecessary code - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack --- kernel/workqueue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c41c3c17b86a..5fea7dc9180f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1324,6 +1324,9 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, { struct worker_pool *pool = pwq->pool; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(>entry, head); -- 2.18.0
[PATCH v3 0/6] kasan: add workqueue and timer stack for generic KASAN
Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. In some of these access/allocation happened in process_one_work(), we see the free stack is useless in KASAN report, it doesn't help programmers to solve UAF on workqueue. The same may stand for times. This patchset improves KASAN reports by making them to have workqueue queueing stack and timer stack information. It is useful for programmers to solve use-after-free or double-free memory issue. Generic KASAN also records the last two workqueue and timer stacks and prints them in KASAN report. It is only suitable for generic KASAN. [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Walter Wu (6): timer: kasan: record timer stack workqueue: kasan: record workqueue stack kasan: print timer and workqueue stack lib/test_kasan.c: add timer test case lib/test_kasan.c: add workqueue test case kasan: update documentation for generic kasan --- Changes since v2: - modify kasan document to be more readable. Thanks for Marco suggestion. Changes since v1: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. - change the aux stack title for common name. --- Documentation/dev-tools/kasan.rst | 4 ++-- kernel/time/timer.c | 3 +++ kernel/workqueue.c| 3 +++ lib/test_kasan.c | 54 ++ mm/kasan/report.c | 4 ++-- 5 files changed, 64 insertions(+), 4 deletions(-)
[PATCH v2 6/6] kasan: update documentation for generic kasan
Generic KASAN support to record the last two timer and workqueue stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index fede42e6536b..5a4c5da8bda8 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,8 +193,8 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. -Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one -and the second to last. +Generic KASAN prints up to 2 call_rcu() call stacks, timer queueing stacks, +or workqueue queueing stacks in reports, the last one and the second to last. Software tag-based KASAN -- 2.18.0
[PATCH v2 5/6] kasan: add tests for workqueue stack recording
Adds a test to verify workqueue stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_workqueue_uaf Freed by task 54: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_workqueue_work+0xc/0x18 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_wq_stack+0xa8/0xb8 insert_work+0x48/0x288 __queue_work+0x3e8/0xc40 queue_work_on+0xf4/0x118 kasan_workqueue_uaf+0xfc/0x190 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov --- lib/test_kasan.c | 29 + 1 file changed, 29 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 2bd61674c7a3..7293a55ff51c 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -845,6 +845,34 @@ static noinline void __init kasan_timer_uaf(void) ((volatile struct timer_list *)timer)->expires; } +static noinline void __init kasan_workqueue_work(struct work_struct *work) +{ + kfree(work); +} + +static noinline void __init kasan_workqueue_uaf(void) +{ + struct workqueue_struct *workqueue; + struct work_struct *work; + + workqueue = create_workqueue("kasan_wq_test"); + if (!workqueue) { + pr_err("Allocation failed\n"); + return; + } + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + pr_err("Allocation failed\n"); + return; + } + + INIT_WORK(work, kasan_workqueue_work); + queue_work(workqueue, work); + destroy_workqueue(workqueue); + + pr_info("use-after-free on workqueue\n"); + ((volatile struct work_struct *)work)->data; +} static int __init kmalloc_tests_init(void) { /* @@ -894,6 +922,7 @@ static int __init kmalloc_tests_init(void) vmalloc_oob(); kasan_rcu_uaf(); kasan_timer_uaf(); + kasan_workqueue_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v2 4/6] kasan: add tests for timer stack recording
Adds a test to verify timer stack recording and print it in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_timer_uaf Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_timer_function+0x1c/0x28 Last potentially related work creation: kasan_save_stack+0x24/0x50 kasan_record_tmr_stack+0xa8/0xb8 init_timer_key+0xf0/0x248 kasan_timer_uaf+0x5c/0xd8 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov --- lib/test_kasan.c | 25 + 1 file changed, 25 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 6e5fb05d42d8..2bd61674c7a3 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -821,6 +821,30 @@ static noinline void __init kasan_rcu_uaf(void) call_rcu(_ptr->rcu, kasan_rcu_reclaim); } +static noinline void __init kasan_timer_function(struct timer_list *timer) +{ + del_timer(timer); + kfree(timer); +} + +static noinline void __init kasan_timer_uaf(void) +{ + struct timer_list *timer; + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) { + pr_err("Allocation failed\n"); + return; + } + + timer_setup(timer, kasan_timer_function, 0); + add_timer(timer); + msleep(100); + + pr_info("use-after-free on timer\n"); + ((volatile struct timer_list *)timer)->expires; +} + static int __init kmalloc_tests_init(void) { /* @@ -869,6 +893,7 @@ static int __init kmalloc_tests_init(void) kmalloc_double_kzfree(); vmalloc_oob(); kasan_rcu_uaf(); + kasan_timer_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v2 3/6] kasan: print timer and workqueue stack
The aux_stack[2] is reused to record the call_rcu() call stack, timer init call stack, and enqueuing work call stacks. So that we need to change the auxiliary stack title for common title, print them in KASAN report. Signed-off-by: Walter Wu Suggested-by: Marco Elver Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko --- v2: - Thanks for Marco suggestion. - We modify aux stack title name in KASAN report in order to print call_rcu()/timer/workqueue stack. --- mm/kasan/report.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 4f49fa6cd1aa..886809d0a8dd 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -183,12 +183,12 @@ static void describe_object(struct kmem_cache *cache, void *object, #ifdef CONFIG_KASAN_GENERIC if (alloc_info->aux_stack[0]) { - pr_err("Last call_rcu():\n"); + pr_err("Last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[0]); pr_err("\n"); } if (alloc_info->aux_stack[1]) { - pr_err("Second to last call_rcu():\n"); + pr_err("Second to last potentially related work creation:\n"); print_stack(alloc_info->aux_stack[1]); pr_err("\n"); } -- 2.18.0
[PATCH v2 2/6] workqueue: kasan: record workqueue stack
Records the last two enqueuing work call stacks in order to print them in KASAN report. It is useful for programmers to solve use-after-free or double-free memory workqueue issue. For workqueue it has turned out to be useful to record the enqueuing work call stacks. Because user can see KASAN report to determine whether it is root cause. They don't need to enable debugobjects, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Tejun Heo Cc: Lai Jiangshan --- v2: - Thanks for Marco suggestion. - Remove unnecessary code - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack --- kernel/workqueue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c41c3c17b86a..5fea7dc9180f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1324,6 +1324,9 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, { struct worker_pool *pool = pwq->pool; + /* record the work call stack in order to print it in KASAN reports */ + kasan_record_aux_stack(work); + /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(>entry, head); -- 2.18.0
[PATCH v2 1/6] timer: kasan: record timer stack
When analyze use-after-free or double-free issue, recording the timer stacks is helpful to to preserve usage history which potentially gives a hint about the affected code. Record the most recent two timer init calls in KASAN which are printed on failure in the KASAN report. For timers it has turned out to be useful to record the stack trace of the timer init call. Because if the UAF root cause is in timer init, then user can see KASAN report to get where it is registered and find out the root cause. It don't need to enable DEBUG_OBJECTS_TIMERS, but they have a chance to find out the root cause. Signed-off-by: Walter Wu Suggested-by: Marco Elver Suggested-by: Thomas Gleixner Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd --- v2: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. --- kernel/time/timer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index a16764b0116e..1ed8f8aca7f5 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -796,6 +796,9 @@ static void do_init_timer(struct timer_list *timer, timer->function = func; timer->flags = flags | raw_smp_processor_id(); lockdep_init_map(>lockdep_map, name, key, 0); + + /* record the timer stack in order to print it in KASAN report */ + kasan_record_aux_stack(timer); } /** -- 2.18.0
[PATCH v2 0/6] kasan: add workqueue and timer stack for generic KASAN
Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. In some of these access/allocation happened in process_one_work(), we see the free stack is useless in KASAN report, it doesn't help programmers to solve UAF on workqueue. The same may stand for times. This patchset improves KASAN reports by making them to have workqueue queueing stack and timer queueing stack information. It is useful for programmers to solve use-after-free or double-free memory issue. Generic KASAN will record the last two workqueue and timer stacks, print them in KASAN report. It is only suitable for generic KASAN. [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Walter Wu (6): timer: kasan: record timer stack workqueue: kasan: record workqueue stack kasan: print timer and workqueue stack lib/test_kasan.c: add timer test case lib/test_kasan.c: add workqueue test case kasan: update documentation for generic kasan --- Changes since v1: - Thanks for Marco and Thomas suggestion. - Remove unnecessary code and fix commit log - reuse kasan_record_aux_stack() and aux_stack to record timer and workqueue stack. - change the aux stack title for common name. --- Documentation/dev-tools/kasan.rst | 4 ++-- kernel/time/timer.c | 3 +++ kernel/workqueue.c| 3 +++ lib/test_kasan.c | 54 ++ mm/kasan/report.c | 4 ++-- 5 files changed, 64 insertions(+), 4 deletions(-)
Re: [PATCH 1/5] timer: kasan: record and print timer stack
Hi Thomas, Please ignore my previous mail. Thanks. On Thu, 2020-08-13 at 13:48 +0200, Thomas Gleixner wrote: > Walter, > > Walter Wu writes: > > This patch records the last two timer queueing stacks and prints > > "This patch" is useless information as we already know from the subject > line that this is a patch. > > git grep 'This patch' Documentation/process/ > Thanks for your information. > > up to 2 timer stacks in KASAN report. It is useful for programmers > > to solve use-after-free or double-free memory timer issues. > > > > When timer_setup() or timer_setup_on_stack() is called, then it > > prepares to use this timer and sets timer callback, we store > > this call stack in order to print it in KASAN report. > > we store nothing. Don't impersonate code please. > > Also please structure the changelog in a way that it's easy to > understand what this is about instead of telling first what the patch > does and then some half baken information why this is useful followed by > more information about what it does. > > Something like this: > > For analysing use after free or double free of objects it is helpful > to preserve usage history which potentially gives a hint about the > affected code. > > For timers it has turned out to be useful to record the stack trace > of the timer init call. > > Record the most recent two timer init calls in KASAN which are printed > on failure in the KASAN report. > > See, this gives a clear context, an explanation why it is useful and a > high level description of what it does. The details are in the patch > ifself and do not have to be epxlained in the changelog. > Thanks for your explanation, Our patch will use this as a template from now on. > For the technical explanation which you need to add, you really need to > tell what's the advantage or additional coverage vs. existing debug > facilities like debugobjects. Just claiming that it's useful does not > make an argument. > We originally wanted him to have similar functions. Maybe he can't completely replace, but KASAN can ave this ability. > The UAF problem with timers is nasty because if you free an active timer > then either the softirq which expires the timer will corrupt potentially > reused memory or the reuse will corrupt the linked list which makes the > softirq or some unrelated code which adds/removes a different timer > explode in undebuggable ways. debugobject prevents that because it > tracks per timer state and invokes the fixup function which keeps the > system alive and also tells you exactly where the free of the active > object happens which is the really interesting place to look at. The > init function is pretty uninteresting in that case because you really > want to know where the freeing of the active object happens. > > So if KASAN detects UAF in the timer softirq then the init trace is not > giving any information especially not in cases where the timer is part > of a common and frequently allocated/freed other data structure. > I don't have experience using this tool, but I will survey it. > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > static inline void kasan_record_aux_stack(void *ptr) {} > > +static inline void kasan_record_tmr_stack(void *ptr) {} > > Duh, so you are adding per object type functions and storage? That's > going to be a huge copy and pasta orgy as every object requires the same > code and extra storage space. > > Why not just using kasan_record_aux_stack() for all of this? > > The 'call_rcu' 'timer' 'whatever next' printout is not really required > because the stack trace already tells you the function which was > invoked. If TOS is call_rcu() or do_timer_init() then it's entirely > clear which object is affected. If the two aux records are not enough > then making the array larger is not the end of the world. > My previous mail say that we will re-use kasan_record_aux_stack() and only have aux_stack. > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/time/timer.c b/kernel/time/timer.c > > index a5221abb4594..ef2da9ddfac7 100644 > > --- a/kernel/time/timer.c > > +++ b/kernel/time/timer.c > > @@ -783,6 +783,8 @@ static void do_init_timer(struct timer_list *timer, > > timer->function = func; > > timer->flags = flags | raw_smp_processor_id(); > > lockdep_init_map(>lockdep_map, name, key, 0); > > + > > + kasan_record_tmr_stack(timer); > > } > > Are you sure this is correct for all timers? > > This is also called for timers whi
Re: [PATCH 1/5] timer: kasan: record and print timer stack
On Thu, 2020-08-13 at 13:48 +0200, Thomas Gleixner wrote: > Walter, > > Walter Wu writes: > > This patch records the last two timer queueing stacks and prints > > "This patch" is useless information as we already know from the subject > line that this is a patch. > > git grep 'This patch' Documentation/process/ > Thanks for your information. > > up to 2 timer stacks in KASAN report. It is useful for programmers > > to solve use-after-free or double-free memory timer issues. > > > > When timer_setup() or timer_setup_on_stack() is called, then it > > prepares to use this timer and sets timer callback, we store > > this call stack in order to print it in KASAN report. > > we store nothing. Don't impersonate code please. > > Also please structure the changelog in a way that it's easy to > understand what this is about instead of telling first what the patch > does and then some half baken information why this is useful followed by > more information about what it does. > > Something like this: > > For analysing use after free or double free of objects it is helpful > to preserve usage history which potentially gives a hint about the > affected code. > > For timers it has turned out to be useful to record the stack trace > of the timer init call. > > Record the most recent two timer init calls in KASAN which are printed > on failure in the KASAN report. > > See, this gives a clear context, an explanation why it is useful and a > high level description of what it does. The details are in the patch > ifself and do not have to be epxlained in the changelog. > > For the technical explanation which you need to add, you really need to > tell what's the advantage or additional coverage vs. existing debug > facilities like debugobjects. Just claiming that it's useful does not > make an argument. > > The UAF problem with timers is nasty because if you free an active timer > then either the softirq which expires the timer will corrupt potentially > reused memory or the reuse will corrupt the linked list which makes the > softirq or some unrelated code which adds/removes a different timer > explode in undebuggable ways. debugobject prevents that because it > tracks per timer state and invokes the fixup function which keeps the > system alive and also tells you exactly where the free of the active > object happens which is the really interesting place to look at. The > init function is pretty uninteresting in that case because you really > want to know where the freeing of the active object happens. > It is what we want to achieve, maybe we have shortcomings, but my patch > So if KASAN detects UAF in the timer softirq then the init trace is not > giving any information especially not in cases where the timer is part > of a common and frequently allocated/freed other data structure. > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > static inline void kasan_record_aux_stack(void *ptr) {} > > +static inline void kasan_record_tmr_stack(void *ptr) {} > > Duh, so you are adding per object type functions and storage? That's > going to be a huge copy and pasta orgy as every object requires the same > code and extra storage space. > > Why not just using kasan_record_aux_stack() for all of this? > > The 'call_rcu' 'timer' 'whatever next' printout is not really required > because the stack trace already tells you the function which was > invoked. If TOS is call_rcu() or do_timer_init() then it's entirely > clear which object is affected. If the two aux records are not enough > then making the array larger is not the end of the world. > > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/time/timer.c b/kernel/time/timer.c > > index a5221abb4594..ef2da9ddfac7 100644 > > --- a/kernel/time/timer.c > > +++ b/kernel/time/timer.c > > @@ -783,6 +783,8 @@ static void do_init_timer(struct timer_list *timer, > > timer->function = func; > > timer->flags = flags | raw_smp_processor_id(); > > lockdep_init_map(>lockdep_map, name, key, 0); > > + > > + kasan_record_tmr_stack(timer); > > } > > Are you sure this is correct for all timers? > > This is also called for timers which are temporarily allocated on stack > and for timers which are statically allocated at compile time. How is > that supposed to work? > > These kind of things want to be explained upfront an not left to the > reviewer as an exercise. > > Thanks, > > tglx I have already
Re: [PATCH 1/5] timer: kasan: record and print timer stack
On Wed, 2020-08-12 at 16:13 +0200, Marco Elver wrote: > On Mon, 10 Aug 2020 at 09:23, Walter Wu wrote: > > This patch records the last two timer queueing stacks and prints > > up to 2 timer stacks in KASAN report. It is useful for programmers > > to solve use-after-free or double-free memory timer issues. > > > > When timer_setup() or timer_setup_on_stack() is called, then it > > prepares to use this timer and sets timer callback, we store > > this call stack in order to print it in KASAN report. > > > > Signed-off-by: Walter Wu > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Thomas Gleixner > > Cc: John Stultz > > Cc: Stephen Boyd > > Cc: Andrew Morton > > --- > > include/linux/kasan.h | 2 ++ > > kernel/time/timer.c | 2 ++ > > mm/kasan/generic.c| 21 + > > mm/kasan/kasan.h | 4 +++- > > mm/kasan/report.c | 11 +++ > > 5 files changed, 39 insertions(+), 1 deletion(-) > > I'm commenting on the code here, but it also applies to patch 2/5, as > it's almost a copy-paste. > > In general, I'd say the solution to get this feature is poorly > designed, resulting in excessive LOC added. The logic added already > exists for the aux stacks. > That's true, we will have refactoring for it. > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 23b7ee00572d..763664b36dc6 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -175,12 +175,14 @@ static inline size_t kasan_metadata_size(struct > > kmem_cache *cache) { return 0; } > > void kasan_cache_shrink(struct kmem_cache *cache); > > void kasan_cache_shutdown(struct kmem_cache *cache); > > void kasan_record_aux_stack(void *ptr); > > +void kasan_record_tmr_stack(void *ptr); > > > > #else /* CONFIG_KASAN_GENERIC */ > > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > static inline void kasan_record_aux_stack(void *ptr) {} > > +static inline void kasan_record_tmr_stack(void *ptr) {} > > It appears that the 'aux' stack is currently only used for call_rcu > stacks, but this interface does not inherently tie it to call_rcu. The > only thing tying it to call_rcu is the fact that the report calls out > call_rcu. > > > /** > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 4b3cbad7431b..f35dcec990ab 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -347,6 +347,27 @@ void kasan_record_aux_stack(void *addr) > > alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); > > } > > > > +void kasan_record_tmr_stack(void *addr) > > +{ > > + struct page *page = kasan_addr_to_page(addr); > > + struct kmem_cache *cache; > > + struct kasan_alloc_meta *alloc_info; > > + void *object; > > + > > + if (!(page && PageSlab(page))) > > + return; > > + > > + cache = page->slab_cache; > > + object = nearest_obj(cache, page, addr); > > + alloc_info = get_alloc_info(cache, object); > > + > > + /* > > +* record the last two timer stacks. > > +*/ > > + alloc_info->tmr_stack[1] = alloc_info->tmr_stack[0]; > > + alloc_info->tmr_stack[0] = kasan_save_stack(GFP_NOWAIT); > > +} > > The solution here is, unfortunately, poorly designed. This is a > copy-paste of the kasan_record_aux_stack() function. > kasan_record_aux_stack() will be re-used for call_rcu, timer, and workqueue. > > void kasan_set_free_info(struct kmem_cache *cache, > > void *object, u8 tag) > > { > > diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h > > index ef655a1c6e15..c50827f388a3 100644 > > --- a/mm/kasan/kasan.h > > +++ b/mm/kasan/kasan.h > > @@ -108,10 +108,12 @@ struct kasan_alloc_meta { > > struct kasan_track alloc_track; > > #ifdef CONFIG_KASAN_GENERIC > > /* > > -* call_rcu() call stack is stored into struct kasan_alloc_meta. > > +* call_rcu() call stack and timer queueing stack are stored > > +* into struct kasan_alloc_meta. > > * The free stack is stored into struct kasan_free_meta. > > */ > > depot_stack_handle_t aux_stack[2]; > > + depot_stack_handle_t tmr_stack[2]; > > #else > > struct kasan_tr
Re: [PATCH 0/5] kasan: add workqueue and timer stack for generic KASAN
On Mon, 2020-08-10 at 08:44 -0400, Qian Cai wrote: > On Mon, Aug 10, 2020 at 07:50:57PM +0800, Walter Wu wrote: > > On Mon, 2020-08-10 at 07:19 -0400, Qian Cai wrote: > > > > > > > On Aug 10, 2020, at 3:21 AM, Walter Wu > > > > wrote: > > > > > > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. > > > > In some of these access/allocation happened in process_one_work(), > > > > we see the free stack is useless in KASAN report, it doesn't help > > > > programmers to solve UAF on workqueue. The same may stand for times. > > > > > > > > This patchset improves KASAN reports by making them to have workqueue > > > > queueing stack and timer queueing stack information. It is useful for > > > > programmers to solve use-after-free or double-free memory issue. > > > > > > > > Generic KASAN will record the last two workqueue and timer stacks, > > > > print them in KASAN report. It is only suitable for generic KASAN. > > > > > > > > In order to print the last two workqueue and timer stacks, so that > > > > we add new members in struct kasan_alloc_meta. > > > > - two workqueue queueing work stacks, total size is 8 bytes. > > > > - two timer queueing stacks, total size is 8 bytes. > > > > > > > > Orignial struct kasan_alloc_meta size is 16 bytes. After add new > > > > members, then the struct kasan_alloc_meta total size is 32 bytes, > > > > It is a good number of alignment. Let it get better memory consumption. > > > > > > Getting debugging tools complicated surely is the best way to kill it. I > > > would argue that it only make sense to complicate it if it is useful most > > > of the time which I never feel or hear that is the case. This reminds me > > > your recent call_rcu() stacks that most of time just makes parsing the > > > report cumbersome. Thus, I urge this exercise to over-engineer on special > > > cases need to stop entirely. > > > > > > > A good debug tool is to have complete information in order to solve > > issue. We should focus on if KASAN reports always show this debug > > information or create a option to decide if show it. Because this > > feature is Dimitry's suggestion. see [1]. So I think it need to be > > implemented. Maybe we can wait his response. > > > > [1]https://lkml.org/lkml/2020/6/23/256 > > I don't know if it is Dmitry's pipe-dream which every KASAN report would > enable > developers to fix it without reproducing it. It is always an ongoing > struggling > between to make kernel easier to debug and the things less cumbersome. > > On the other hand, Dmitry's suggestion makes sense only if the price we are > going to pay is fair. With the current diffstat and the recent experience of > call_rcu() stacks "waste" screen spaces as a heavy KASAN user myself, I can't > really get that exciting for pushing the limit again at all. > If you are concerned that the report is long, maybe we can create an option for the user decide whether print them (include call_rcu). So this should satisfy everyone? > > > > > > > > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work > > > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers > > > > [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > Walter Wu (5): > > > > timer: kasan: record and print timer stack > > > > workqueue: kasan: record and print workqueue stack > > > > lib/test_kasan.c: add timer test case > > > > lib/test_kasan.c: add workqueue test case > > > > kasan: update documentation for generic kasan > > > > > > > > Documentation/dev-tools/kasan.rst | 4 ++-- > > > > include/linux/kasan.h | 4 > > > > kernel/time/timer.c | 2 ++ > > > > kernel/workqueue.c| 3 +++ > > > > lib/test_kasan.c | 54 > > > > ++ > > > > mm/kasan/generic.c| 42 > > > > ++ > > > > mm/kasan/kasan.h | 6 +- > > > > mm/kasan/report.c | 22 ++ > > > > 8 files changed, 134 insertions(+), 3 deletions(-) > > > > > > > > -- > > > > You received this message because you are subscribed to the Google > > > > Groups "kasan-dev" group. > > > > To unsubscribe from this group and stop receiving emails from it, send > > > > an email to kasan-dev+unsubscr...@googlegroups.com. > > > > To view this discussion on the web visit > > > > https://groups.google.com/d/msgid/kasan-dev/20200810072115.429-1-walter-zh.wu%40mediatek.com. > >
Re: [PATCH 0/5] kasan: add workqueue and timer stack for generic KASAN
On Mon, 2020-08-10 at 19:50 +0800, Walter Wu wrote: > On Mon, 2020-08-10 at 07:19 -0400, Qian Cai wrote: > > > > > On Aug 10, 2020, at 3:21 AM, Walter Wu wrote: > > > > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. > > > In some of these access/allocation happened in process_one_work(), > > > we see the free stack is useless in KASAN report, it doesn't help > > > programmers to solve UAF on workqueue. The same may stand for times. > > > > > > This patchset improves KASAN reports by making them to have workqueue > > > queueing stack and timer queueing stack information. It is useful for > > > programmers to solve use-after-free or double-free memory issue. > > > > > > Generic KASAN will record the last two workqueue and timer stacks, > > > print them in KASAN report. It is only suitable for generic KASAN. > > > > > > In order to print the last two workqueue and timer stacks, so that > > > we add new members in struct kasan_alloc_meta. > > > - two workqueue queueing work stacks, total size is 8 bytes. > > > - two timer queueing stacks, total size is 8 bytes. > > > > > > Orignial struct kasan_alloc_meta size is 16 bytes. After add new > > > members, then the struct kasan_alloc_meta total size is 32 bytes, > > > It is a good number of alignment. Let it get better memory consumption. > > > > Getting debugging tools complicated surely is the best way to kill it. I > > would argue that it only make sense to complicate it if it is useful most > > of the time which I never feel or hear that is the case. This reminds me > > your recent call_rcu() stacks that most of time just makes parsing the > > report cumbersome. Thus, I urge this exercise to over-engineer on special > > cases need to stop entirely. > > > > A good debug tool is to have complete information in order to solve > issue. We should focus on if KASAN reports always show this debug > information or create a option to decide if show it. Because this > feature is Dmitry's suggestion. see [1]. So I think it need to be > implemented. Maybe we can wait his response. > > [1]https://lkml.org/lkml/2020/6/23/256 > > Thanks. > Fix name typo. I am sorry to him. And add a bugzilla to show why need to do it. please see [1]. [1] https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work > > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers > > > [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > Walter Wu (5): > > > timer: kasan: record and print timer stack > > > workqueue: kasan: record and print workqueue stack > > > lib/test_kasan.c: add timer test case > > > lib/test_kasan.c: add workqueue test case > > > kasan: update documentation for generic kasan > > > > > > Documentation/dev-tools/kasan.rst | 4 ++-- > > > include/linux/kasan.h | 4 > > > kernel/time/timer.c | 2 ++ > > > kernel/workqueue.c| 3 +++ > > > lib/test_kasan.c | 54 > > > ++ > > > mm/kasan/generic.c| 42 > > > ++ > > > mm/kasan/kasan.h | 6 +- > > > mm/kasan/report.c | 22 ++ > > > 8 files changed, 134 insertions(+), 3 deletions(-) > > > > > > -- > > > You received this message because you are subscribed to the Google Groups > > > "kasan-dev" group. > > > To unsubscribe from this group and stop receiving emails from it, send an > > > email to kasan-dev+unsubscr...@googlegroups.com. > > > To view this discussion on the web visit > > > https://groups.google.com/d/msgid/kasan-dev/20200810072115.429-1-walter-zh.wu%40mediatek.com. >
Re: [PATCH 0/5] kasan: add workqueue and timer stack for generic KASAN
On Mon, 2020-08-10 at 07:19 -0400, Qian Cai wrote: > > > On Aug 10, 2020, at 3:21 AM, Walter Wu wrote: > > > > Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. > > In some of these access/allocation happened in process_one_work(), > > we see the free stack is useless in KASAN report, it doesn't help > > programmers to solve UAF on workqueue. The same may stand for times. > > > > This patchset improves KASAN reports by making them to have workqueue > > queueing stack and timer queueing stack information. It is useful for > > programmers to solve use-after-free or double-free memory issue. > > > > Generic KASAN will record the last two workqueue and timer stacks, > > print them in KASAN report. It is only suitable for generic KASAN. > > > > In order to print the last two workqueue and timer stacks, so that > > we add new members in struct kasan_alloc_meta. > > - two workqueue queueing work stacks, total size is 8 bytes. > > - two timer queueing stacks, total size is 8 bytes. > > > > Orignial struct kasan_alloc_meta size is 16 bytes. After add new > > members, then the struct kasan_alloc_meta total size is 32 bytes, > > It is a good number of alignment. Let it get better memory consumption. > > Getting debugging tools complicated surely is the best way to kill it. I > would argue that it only make sense to complicate it if it is useful most of > the time which I never feel or hear that is the case. This reminds me your > recent call_rcu() stacks that most of time just makes parsing the report > cumbersome. Thus, I urge this exercise to over-engineer on special cases need > to stop entirely. > A good debug tool is to have complete information in order to solve issue. We should focus on if KASAN reports always show this debug information or create a option to decide if show it. Because this feature is Dimitry's suggestion. see [1]. So I think it need to be implemented. Maybe we can wait his response. [1]https://lkml.org/lkml/2020/6/23/256 Thanks. > > > > [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work > > [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers > > [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > Walter Wu (5): > > timer: kasan: record and print timer stack > > workqueue: kasan: record and print workqueue stack > > lib/test_kasan.c: add timer test case > > lib/test_kasan.c: add workqueue test case > > kasan: update documentation for generic kasan > > > > Documentation/dev-tools/kasan.rst | 4 ++-- > > include/linux/kasan.h | 4 > > kernel/time/timer.c | 2 ++ > > kernel/workqueue.c| 3 +++ > > lib/test_kasan.c | 54 > > ++ > > mm/kasan/generic.c| 42 > > ++ > > mm/kasan/kasan.h | 6 +- > > mm/kasan/report.c | 22 ++ > > 8 files changed, 134 insertions(+), 3 deletions(-) > > > > -- > > You received this message because you are subscribed to the Google Groups > > "kasan-dev" group. > > To unsubscribe from this group and stop receiving emails from it, send an > > email to kasan-dev+unsubscr...@googlegroups.com. > > To view this discussion on the web visit > > https://groups.google.com/d/msgid/kasan-dev/20200810072115.429-1-walter-zh.wu%40mediatek.com.
[PATCH 5/5] kasan: update documentation for generic KASAN
Generic KASAN support to record the last two timer and workqueue stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index fede42e6536b..5a4c5da8bda8 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,8 +193,8 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. -Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one -and the second to last. +Generic KASAN prints up to 2 call_rcu() call stacks, timer queueing stacks, +and workqueue queueing stacks in reports, the last one and the second to last. Software tag-based KASAN -- 2.18.0
[PATCH 4/5] lib/test_kasan.c: add workqueue test case
Adds a test case to verify workqueue stack recording and print the last workqueue stack in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_workqueue_uaf Freed by task 54: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_workqueue_work+0xc/0x18 Last workqueue stack: kasan_save_stack+0x24/0x50 kasan_record_wq_stack+0xa8/0xb8 insert_work+0x48/0x288 __queue_work+0x3e8/0xc40 queue_work_on+0xf4/0x118 kasan_workqueue_uaf+0xfc/0x190 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index c3c6e22ec959..2c6c20cd154b 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -869,6 +869,35 @@ static noinline void __init kasan_timer_uaf(void) ((volatile struct timer_list *)timer)->expires; } +static noinline void __init kasan_workqueue_work(struct work_struct *work) +{ + kfree(work); +} + +static noinline void __init kasan_workqueue_uaf(void) +{ + struct workqueue_struct *workqueue; + struct work_struct *work; + + workqueue = create_workqueue("kasan_wq_test"); + if (!workqueue) { + pr_err("Allocation failed\n"); + return; + } + work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); + if (!work) { + pr_err("Allocation failed\n"); + return; + } + + INIT_WORK(work, kasan_workqueue_work); + queue_work(workqueue, work); + destroy_workqueue(workqueue); + + pr_info("use-after-free on workqueue\n"); + ((volatile struct work_struct *)work)->data; +} + static int __init kmalloc_tests_init(void) { /* @@ -918,6 +947,7 @@ static int __init kmalloc_tests_init(void) vmalloc_oob(); kasan_rcu_uaf(); kasan_timer_uaf(); + kasan_workqueue_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH 3/5] lib/test_kasan.c: add timer test case
Adds a test case to verify timer stack recording and print the last timer stack in KASAN report. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_timer_uaf Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x20/0x40 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_timer_function+0x1c/0x28 Last timer stack: kasan_save_stack+0x24/0x50 kasan_record_tmr_stack+0xa8/0xb8 init_timer_key+0xf0/0x248 kasan_timer_uaf+0x5c/0xd8 Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger --- lib/test_kasan.c | 25 + 1 file changed, 25 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 6e5fb05d42d8..2bd61674c7a3 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -821,6 +821,30 @@ static noinline void __init kasan_rcu_uaf(void) call_rcu(_ptr->rcu, kasan_rcu_reclaim); } +static noinline void __init kasan_timer_function(struct timer_list *timer) +{ + del_timer(timer); + kfree(timer); +} + +static noinline void __init kasan_timer_uaf(void) +{ + struct timer_list *timer; + + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) { + pr_err("Allocation failed\n"); + return; + } + + timer_setup(timer, kasan_timer_function, 0); + add_timer(timer); + msleep(100); + + pr_info("use-after-free on timer\n"); + ((volatile struct timer_list *)timer)->expires; +} + static int __init kmalloc_tests_init(void) { /* @@ -869,6 +893,7 @@ static int __init kmalloc_tests_init(void) kmalloc_double_kzfree(); vmalloc_oob(); kasan_rcu_uaf(); + kasan_timer_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH 2/5] workqueue: kasan: record and print workqueue stack
This patch records the last two enqueueing work call stacks on workqueue and prints up to 2 workqueue stacks in KASAN report. It is useful for programmers to solve use-after-free or double-free memory wq issue. When queue_work() is called, then queue the work into a workqueue, we store this call stack in order to print it in KASAN report. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Tejun Heo Cc: Lai Jiangshan Cc: Andrew Morton --- include/linux/kasan.h | 2 ++ kernel/workqueue.c| 3 +++ mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 8 +--- mm/kasan/report.c | 11 +++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 43ae040ae9b2..687cbf2faf83 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,6 +174,7 @@ void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); void kasan_record_aux_stack(void *ptr); void kasan_record_tmr_stack(void *ptr); +void kasan_record_wq_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ @@ -181,6 +182,7 @@ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} static inline void kasan_record_aux_stack(void *ptr) {} static inline void kasan_record_tmr_stack(void *ptr) {} +static inline void kasan_record_wq_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c41c3c17b86a..0e5963e06730 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1324,6 +1324,9 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, { struct worker_pool *pool = pwq->pool; + /* record the work in order to print it in KASAN reports */ + kasan_record_wq_stack(work); + /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(>entry, head); diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 627792d11569..592dc58fbe42 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -367,6 +367,27 @@ void kasan_record_tmr_stack(void *addr) alloc_info->tmr_stack[0] = kasan_save_stack(GFP_NOWAIT); } +void kasan_record_wq_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two workqueue stacks. +*/ + alloc_info->wq_stack[1] = alloc_info->wq_stack[0]; + alloc_info->wq_stack[0] = kasan_save_stack(GFP_NOWAIT); +} + void kasan_set_free_info(struct kmem_cache *cache, void *object, u8 tag) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 4059f327767c..a4f76b1bde0a 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -108,12 +108,14 @@ struct kasan_alloc_meta { struct kasan_track alloc_track; #ifdef CONFIG_KASAN_GENERIC /* -* call_rcu() call stack and timer queueing stack are stored -* into struct kasan_alloc_meta. -* The free stack is stored into struct kasan_free_meta. +* call_rcu() call stack, timer queueing stack, and workqueue +* queueing stack are stored into kasan_alloc_meta. +* +* With generic KASAN the free stack is stored into kasan_free_meta. */ depot_stack_handle_t aux_stack[2]; depot_stack_handle_t tmr_stack[2]; + depot_stack_handle_t wq_stack[2]; #else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; #endif diff --git a/mm/kasan/report.c b/mm/kasan/report.c index f602f090d90b..e6bc470fcd0a 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -203,6 +203,17 @@ static void describe_object(struct kmem_cache *cache, void *object, print_stack(alloc_info->tmr_stack[1]); pr_err("\n"); } + + if (alloc_info->wq_stack[0]) { + pr_err("Last workqueue stack:\n"); + print_stack(alloc_info->wq_stack[0]); + pr_err("\n"); + } + if (alloc_info->wq_stack[1]) { + pr_err("Second to last workqueue stack:\n"); + print_stack(alloc_info->wq_stack[1]); + pr_err("\n"); + } #endif } -- 2.18.0
[PATCH 1/5] timer: kasan: record and print timer stack
This patch records the last two timer queueing stacks and prints up to 2 timer stacks in KASAN report. It is useful for programmers to solve use-after-free or double-free memory timer issues. When timer_setup() or timer_setup_on_stack() is called, then it prepares to use this timer and sets timer callback, we store this call stack in order to print it in KASAN report. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Thomas Gleixner Cc: John Stultz Cc: Stephen Boyd Cc: Andrew Morton --- include/linux/kasan.h | 2 ++ kernel/time/timer.c | 2 ++ mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 4 +++- mm/kasan/report.c | 11 +++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 23b7ee00572d..763664b36dc6 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -175,12 +175,14 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); void kasan_record_aux_stack(void *ptr); +void kasan_record_tmr_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} static inline void kasan_record_aux_stack(void *ptr) {} +static inline void kasan_record_tmr_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/time/timer.c b/kernel/time/timer.c index a5221abb4594..ef2da9ddfac7 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -783,6 +783,8 @@ static void do_init_timer(struct timer_list *timer, timer->function = func; timer->flags = flags | raw_smp_processor_id(); lockdep_init_map(>lockdep_map, name, key, 0); + + kasan_record_tmr_stack(timer); } /** diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 4b3cbad7431b..f35dcec990ab 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -347,6 +347,27 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } +void kasan_record_tmr_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two timer stacks. +*/ + alloc_info->tmr_stack[1] = alloc_info->tmr_stack[0]; + alloc_info->tmr_stack[0] = kasan_save_stack(GFP_NOWAIT); +} + void kasan_set_free_info(struct kmem_cache *cache, void *object, u8 tag) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index ef655a1c6e15..c50827f388a3 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -108,10 +108,12 @@ struct kasan_alloc_meta { struct kasan_track alloc_track; #ifdef CONFIG_KASAN_GENERIC /* -* call_rcu() call stack is stored into struct kasan_alloc_meta. +* call_rcu() call stack and timer queueing stack are stored +* into struct kasan_alloc_meta. * The free stack is stored into struct kasan_free_meta. */ depot_stack_handle_t aux_stack[2]; + depot_stack_handle_t tmr_stack[2]; #else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; #endif diff --git a/mm/kasan/report.c b/mm/kasan/report.c index fed3c8fdfd25..6fa3bfee381f 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -191,6 +191,17 @@ static void describe_object(struct kmem_cache *cache, void *object, print_stack(alloc_info->aux_stack[1]); pr_err("\n"); } + + if (alloc_info->tmr_stack[0]) { + pr_err("Last timer stack:\n"); + print_stack(alloc_info->tmr_stack[0]); + pr_err("\n"); + } + if (alloc_info->tmr_stack[1]) { + pr_err("Second to last timer stack:\n"); + print_stack(alloc_info->tmr_stack[1]); + pr_err("\n"); + } #endif } -- 2.18.0
[PATCH 0/5] kasan: add workqueue and timer stack for generic KASAN
Syzbot reports many UAF issues for workqueue or timer, see [1] and [2]. In some of these access/allocation happened in process_one_work(), we see the free stack is useless in KASAN report, it doesn't help programmers to solve UAF on workqueue. The same may stand for times. This patchset improves KASAN reports by making them to have workqueue queueing stack and timer queueing stack information. It is useful for programmers to solve use-after-free or double-free memory issue. Generic KASAN will record the last two workqueue and timer stacks, print them in KASAN report. It is only suitable for generic KASAN. In order to print the last two workqueue and timer stacks, so that we add new members in struct kasan_alloc_meta. - two workqueue queueing work stacks, total size is 8 bytes. - two timer queueing stacks, total size is 8 bytes. Orignial struct kasan_alloc_meta size is 16 bytes. After add new members, then the struct kasan_alloc_meta total size is 32 bytes, It is a good number of alignment. Let it get better memory consumption. [1]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22+process_one_work [2]https://groups.google.com/g/syzkaller-bugs/search?q=%22use-after-free%22%20expire_timers [3]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Walter Wu (5): timer: kasan: record and print timer stack workqueue: kasan: record and print workqueue stack lib/test_kasan.c: add timer test case lib/test_kasan.c: add workqueue test case kasan: update documentation for generic kasan Documentation/dev-tools/kasan.rst | 4 ++-- include/linux/kasan.h | 4 kernel/time/timer.c | 2 ++ kernel/workqueue.c| 3 +++ lib/test_kasan.c | 54 ++ mm/kasan/generic.c| 42 ++ mm/kasan/kasan.h | 6 +- mm/kasan/report.c | 22 ++ 8 files changed, 134 insertions(+), 3 deletions(-)
[PATCH v8 4/4] kasan: update documentation for generic kasan
Generic KASAN will support to record the last two call_rcu() call stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c652d740735d..fede42e6536b 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,6 +193,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. +Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one +and the second to last. + Software tag-based KASAN -- 2.18.0
[PATCH v8 3/4] kasan: add tests for call_rcu stack recording
Test call_rcu() call stack recording and verify whether it correctly is printed in KASAN report. Signed-off-by: Walter Wu Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger --- Changes since v6: - renamed the variable name in testcase --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..19c72c1501ef 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -792,6 +792,35 @@ static noinline void __init vmalloc_oob(void) static void __init vmalloc_oob(void) {} #endif +static struct kasan_rcu_info { + int i; + struct rcu_head rcu; +} *global_rcu_ptr; + +static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp) +{ + struct kasan_rcu_info *fp = container_of(rp, + struct kasan_rcu_info, rcu); + + kfree(fp); + fp->i = 1; +} + +static noinline void __init kasan_rcu_uaf(void) +{ + struct kasan_rcu_info *ptr; + + pr_info("use-after-free in kasan_rcu_reclaim\n"); + ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + global_rcu_ptr = rcu_dereference_protected(ptr, NULL); + call_rcu(_rcu_ptr->rcu, kasan_rcu_reclaim); +} + static int __init kmalloc_tests_init(void) { /* @@ -839,6 +868,7 @@ static int __init kmalloc_tests_init(void) kasan_bitops(); kmalloc_double_kzfree(); vmalloc_oob(); + kasan_rcu_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v8 2/4] kasan: record and print the free track
Move free track from kasan_alloc_meta to kasan_free_meta in order to make struct kasan_alloc_meta and kasan_free_meta size are both 16 bytes. It is a good size because it is the minimal redzone size and a good number of alignment. For free track, we make some modifications as shown below: 1) Remove the free_track from struct kasan_alloc_meta. 2) Add the free_track into struct kasan_free_meta. 3) Add a macro KASAN_KMALLOC_FREETRACK in order to check whether it can print free stack in KASAN report. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Co-developed-by: Dmitry Vyukov Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko --- Changes since v7: - fix this commit dependence in the series --- mm/kasan/common.c | 22 ++ mm/kasan/generic.c| 22 ++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 16 +--- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 26 -- mm/kasan/tags.c | 37 + 7 files changed, 80 insertions(+), 45 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 8bc618289bb1..47b53912f322 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) return stack_depot_save(entries, nr_entries, flags); } -static inline void set_track(struct kasan_track *track, gfp_t flags) +void kasan_set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; track->stack = kasan_save_stack(flags); @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, return (void *)object + cache->kasan_info.free_meta_offset; } - -static void kasan_set_free_info(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - u8 idx = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - idx = alloc_meta->free_track_idx; - alloc_meta->free_pointer_tag[idx] = tag; - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; -#endif - - set_track(_meta->free_track[idx], GFP_NOWAIT); -} - void kasan_poison_slab(struct page *page) { unsigned long i; @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_KMALLOC_REDZONE); if (cache->flags & SLAB_KASAN) - set_track(_alloc_info(cache, object)->alloc_track, flags); + kasan_set_track(_alloc_info(cache, object)->alloc_track, flags); return set_tag(object, tag); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 8acf48882ba2..4b3cbad7431b 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -346,3 +346,25 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } + +void kasan_set_free_info(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + kasan_set_track(_meta->free_track, GFP_NOWAIT); + + /* +* the object was freed and has free track set +*/ + *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK; +} + +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag) +{ + if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK) + return NULL; + return _free_info(cache, object)->free_track; +} diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c index e200acb2d292..a38c7a9e192a 100644 --- a/mm/kasan/generic_report.c +++ b/mm/kasan/generic_report.c @@ -80,6 +80,7 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) break; case KASAN_FREE_PAGE: case KASAN_KMALLOC_FREE: + case KASAN_KMALLOC_FREETRACK: bug_type = "use-after-free"; break; case KASAN_ALLOCA_LEFT: diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index b1a88c75416a..ef655a1c6e15 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -17,15 +17,17 @@ #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 */ #else #define KASAN_FREE_PAGE KASAN_TAG_INVALID #define KASAN_PAGE
[PATCH v8 1/4] rcu: kasan: record and print call_rcu() call stack
This feature will record the last two call_rcu() call stacks and prints up to 2 call_rcu() call stacks in KASAN report. When call_rcu() is called, we store the call_rcu() call stack into slub alloc meta-data, so that the KASAN report can print rcu stack. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Acked-by: Paul E. McKenney Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Andrew Morton Cc: Josh Triplett Cc: Mathieu Desnoyers Cc: Lai Jiangshan Cc: Joel Fernandes --- Changes since v7: - fix this commit dependence in the series Changes since v6: - fix typo --- include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ mm/kasan/common.c | 4 ++-- mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 9 + mm/kasan/report.c | 28 +++- 6 files changed, 59 insertions(+), 7 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 31314ca7c635..23b7ee00572d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); +void kasan_record_aux_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} +static inline void kasan_record_aux_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 06548e2ebb72..36a4ff7f320b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "../time/tick-internal.h" #include "tree.h" @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) head->func = func; head->next = NULL; local_irq_save(flags); + kasan_record_aux_stack(head); rdp = this_cpu_ptr(_data); /* Add the callback to our list. */ diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 2906358e42f0..8bc618289bb1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -41,7 +41,7 @@ #include "kasan.h" #include "../slab.h" -static inline depot_stack_handle_t save_stack(gfp_t flags) +depot_stack_handle_t kasan_save_stack(gfp_t flags) { unsigned long entries[KASAN_STACK_DEPTH]; unsigned int nr_entries; @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) static inline void set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; - track->stack = save_stack(flags); + track->stack = kasan_save_stack(flags); } void kasan_enable_current(void) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 56ff8885fe2e..8acf48882ba2 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); DEFINE_ASAN_SET_SHADOW(f3); DEFINE_ASAN_SET_SHADOW(f5); DEFINE_ASAN_SET_SHADOW(f8); + +void kasan_record_aux_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two call_rcu() call stacks. +*/ + alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e8f37199d885..b1a88c75416a 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -104,6 +104,13 @@ struct kasan_track { struct kasan_alloc_meta { struct kasan_track alloc_track; +#ifdef CONFIG_KASAN_GENERIC + /* +* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The free stack is stored into struct kasan_free_meta. +*/ + depot_stack_handle_t aux_stack[2]; +#endif struct kasan_track free_track[KASAN_NR_FREE_STACKS]; #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY u8 free_pointer_tag[KASAN_NR_FREE_STACKS]; @@ -159,6 +166,8 @@ void kasan_report_invalid_free(void *object, unsigned long ip); struct page *kasan_addr_to_page(const void *addr); +depot_stack_handle_t kasan_save_stack(gfp_t flags); + #if defined(CONFIG_KASAN_GENERIC) && \ (defined(CONFIG_SLAB) || defined(CONFIG_SLUB)) void quarant
[PATCH v8 0/4] kasan: memorize and print call_rcu stack
This patchset improves KASAN reports by making them to have call_rcu() call stack information. It is useful for programmers to solve use-after-free or double-free memory issue. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_rcu_reclaim+0x58/0x60 Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x18/0x20 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_rcu_reclaim+0x1c/0x60 Last call_rcu(): kasan_save_stack+0x24/0x50 kasan_record_aux_stack+0xbc/0xd0 call_rcu+0x8c/0x580 kasan_rcu_uaf+0xf4/0xf8 Generic KASAN will record the last two call_rcu() call stacks and print up to 2 call_rcu() call stacks in KASAN report. it is only suitable for generic KASAN. This feature considers the size of struct kasan_alloc_meta and kasan_free_meta, we try to optimize the structure layout and size , lets it get better memory consumption. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Changes since v1: - remove new config option, default enable it in generic KASAN - test this feature in SLAB/SLUB, it is pass. - modify macro to be more clearly - modify documentation Changes since v2: - change recording from first/last to the last two call stacks - move free track into kasan free meta - init slab_free_meta on object slot creation - modify documentation Changes since v3: - change variable name to be more clearly - remove the redundant condition - remove init free meta-data and increasing object condition Changes since v4: - add a macro KASAN_KMALLOC_FREETRACK in order to check whether print free stack - change printing message - remove descriptions in Kocong.kasan Changes since v5: - reuse print_stack() in print_track() Changes since v6: - fix typo - renamed the variable name in testcase Changes since v7: - fix this commit dependence in the series Walter Wu (4): rcu: kasan: record and print call_rcu() call stack kasan: record and print the free track kasan: add tests for call_rcu stack recording kasan: update documentation for generic kasan Documentation/dev-tools/kasan.rst | 3 +++ include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ lib/test_kasan.c | 30 ++ mm/kasan/common.c | 26 -- mm/kasan/generic.c| 43 +++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 23 +-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 54 +++--- mm/kasan/tags.c | 37 + 11 files changed, 171 insertions(+), 51 deletions(-)
[PATCH v4] kasan: fix KASAN unit tests for tag-based KASAN
We use tag-based KASAN, then KASAN unit tests don't detect out-of-bounds memory access. They need to be fixed. With tag-based KASAN, the state of each 16 aligned bytes of memory is encoded in one shadow byte and the shadow value is tag of pointer, so we need to read next shadow byte, the shadow value is not equal to tag value of pointer, so that tag-based KASAN will detect out-of-bounds memory access. Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Acked-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrew Morton --- changes since v1: - Reduce amount of non-compiled code. - KUnit-KASAN Integration patchset is not merged yet. My patch should have conflict with it, if needed, we can continue to wait it. changes since v2: - Add one marco to make unit tests more readability. changes since v3: - use KASAN_SHADOW_SCALE_SIZE instead of 13. --- lib/test_kasan.c | 49 +++- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 61a3cc11556f..003ea5b49f4c 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -23,6 +23,10 @@ #include +#include "../mm/kasan/kasan.h" + +#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_SHADOW_SCALE_SIZE) + /* * Note: test functions are marked noinline so that their names appear in * reports. @@ -40,7 +44,8 @@ static noinline void __init kmalloc_oob_right(void) return; } - ptr[size] = 'x'; + ptr[size + OOB_TAG_OFF] = 'x'; + kfree(ptr); } @@ -92,7 +97,8 @@ static noinline void __init kmalloc_pagealloc_oob_right(void) return; } - ptr[size] = 0; + ptr[size + OOB_TAG_OFF] = 0; + kfree(ptr); } @@ -162,7 +168,8 @@ static noinline void __init kmalloc_oob_krealloc_more(void) return; } - ptr2[size2] = 'x'; + ptr2[size2 + OOB_TAG_OFF] = 'x'; + kfree(ptr2); } @@ -180,7 +187,9 @@ static noinline void __init kmalloc_oob_krealloc_less(void) kfree(ptr1); return; } - ptr2[size2] = 'x'; + + ptr2[size2 + OOB_TAG_OFF] = 'x'; + kfree(ptr2); } @@ -216,7 +225,8 @@ static noinline void __init kmalloc_oob_memset_2(void) return; } - memset(ptr+7, 0, 2); + memset(ptr + 7 + OOB_TAG_OFF, 0, 2); + kfree(ptr); } @@ -232,7 +242,8 @@ static noinline void __init kmalloc_oob_memset_4(void) return; } - memset(ptr+5, 0, 4); + memset(ptr + 5 + OOB_TAG_OFF, 0, 4); + kfree(ptr); } @@ -249,7 +260,8 @@ static noinline void __init kmalloc_oob_memset_8(void) return; } - memset(ptr+1, 0, 8); + memset(ptr + 1 + OOB_TAG_OFF, 0, 8); + kfree(ptr); } @@ -265,7 +277,8 @@ static noinline void __init kmalloc_oob_memset_16(void) return; } - memset(ptr+1, 0, 16); + memset(ptr + 1 + OOB_TAG_OFF, 0, 16); + kfree(ptr); } @@ -281,7 +294,8 @@ static noinline void __init kmalloc_oob_in_memset(void) return; } - memset(ptr, 0, size+5); + memset(ptr, 0, size + 5 + OOB_TAG_OFF); + kfree(ptr); } @@ -415,7 +429,8 @@ static noinline void __init kmem_cache_oob(void) return; } - *p = p[size]; + *p = p[size + OOB_TAG_OFF]; + kmem_cache_free(cache, p); kmem_cache_destroy(cache); } @@ -512,25 +527,25 @@ static noinline void __init copy_user_test(void) } pr_info("out-of-bounds in copy_from_user()\n"); - unused = copy_from_user(kmem, usermem, size + 1); + unused = copy_from_user(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in copy_to_user()\n"); - unused = copy_to_user(usermem, kmem, size + 1); + unused = copy_to_user(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_from_user()\n"); - unused = __copy_from_user(kmem, usermem, size + 1); + unused = __copy_from_user(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_to_user()\n"); - unused = __copy_to_user(usermem, kmem, size + 1); + unused = __copy_to_user(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_from_user_inatomic()\n"); - unused = __copy_from_user_inatomic(kmem, usermem, size + 1); + unused = __copy_from_user_inatomic(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_to_user_inatomic()\n"); - unused = __copy_to_user_inatomic(usermem, kmem, size + 1); + unused = __copy_to_user_inatomic(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in strn
[PATCH v3] kasan: fix KASAN unit tests for tag-based KASAN
We use tag-based KASAN, then KASAN unit tests don't detect out-of-bounds memory access. They need to be fixed. With tag-based KASAN, the state of each 16 aligned bytes of memory is encoded in one shadow byte and the shadow value is tag of pointer, so we need to read next shadow byte, the shadow value is not equal to tag value of pointer, so that tag-based KASAN will detect out-of-bounds memory access. Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov Cc: Andrew Morton --- changes since v1: - Reduce amount of non-compiled code. - KUnit-KASAN Integration patchset is not merged yet. My patch should have conflict with it, if needed, we can continue to wait it. changes since v2: - Add one marco to make unit tests more readability. --- lib/test_kasan.c | 47 ++- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..b5049a807e25 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -23,6 +23,8 @@ #include +#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : 13) + /* * Note: test functions are marked noinline so that their names appear in * reports. @@ -40,7 +42,8 @@ static noinline void __init kmalloc_oob_right(void) return; } - ptr[size] = 'x'; + ptr[size + OOB_TAG_OFF] = 'x'; + kfree(ptr); } @@ -92,7 +95,8 @@ static noinline void __init kmalloc_pagealloc_oob_right(void) return; } - ptr[size] = 0; + ptr[size + OOB_TAG_OFF] = 0; + kfree(ptr); } @@ -162,7 +166,8 @@ static noinline void __init kmalloc_oob_krealloc_more(void) return; } - ptr2[size2] = 'x'; + ptr2[size2 + OOB_TAG_OFF] = 'x'; + kfree(ptr2); } @@ -180,7 +185,9 @@ static noinline void __init kmalloc_oob_krealloc_less(void) kfree(ptr1); return; } - ptr2[size2] = 'x'; + + ptr2[size2 + OOB_TAG_OFF] = 'x'; + kfree(ptr2); } @@ -216,7 +223,8 @@ static noinline void __init kmalloc_oob_memset_2(void) return; } - memset(ptr+7, 0, 2); + memset(ptr + 7 + OOB_TAG_OFF, 0, 2); + kfree(ptr); } @@ -232,7 +240,8 @@ static noinline void __init kmalloc_oob_memset_4(void) return; } - memset(ptr+5, 0, 4); + memset(ptr + 5 + OOB_TAG_OFF, 0, 4); + kfree(ptr); } @@ -249,7 +258,8 @@ static noinline void __init kmalloc_oob_memset_8(void) return; } - memset(ptr+1, 0, 8); + memset(ptr + 1 + OOB_TAG_OFF, 0, 8); + kfree(ptr); } @@ -265,7 +275,8 @@ static noinline void __init kmalloc_oob_memset_16(void) return; } - memset(ptr+1, 0, 16); + memset(ptr + 1 + OOB_TAG_OFF, 0, 16); + kfree(ptr); } @@ -281,7 +292,8 @@ static noinline void __init kmalloc_oob_in_memset(void) return; } - memset(ptr, 0, size+5); + memset(ptr, 0, size + 5 + OOB_TAG_OFF); + kfree(ptr); } @@ -415,7 +427,8 @@ static noinline void __init kmem_cache_oob(void) return; } - *p = p[size]; + *p = p[size + OOB_TAG_OFF]; + kmem_cache_free(cache, p); kmem_cache_destroy(cache); } @@ -512,25 +525,25 @@ static noinline void __init copy_user_test(void) } pr_info("out-of-bounds in copy_from_user()\n"); - unused = copy_from_user(kmem, usermem, size + 1); + unused = copy_from_user(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in copy_to_user()\n"); - unused = copy_to_user(usermem, kmem, size + 1); + unused = copy_to_user(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_from_user()\n"); - unused = __copy_from_user(kmem, usermem, size + 1); + unused = __copy_from_user(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_to_user()\n"); - unused = __copy_to_user(usermem, kmem, size + 1); + unused = __copy_to_user(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_from_user_inatomic()\n"); - unused = __copy_from_user_inatomic(kmem, usermem, size + 1); + unused = __copy_from_user_inatomic(kmem, usermem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in __copy_to_user_inatomic()\n"); - unused = __copy_to_user_inatomic(usermem, kmem, size + 1); + unused = __copy_to_user_inatomic(usermem, kmem, size + 1 + OOB_TAG_OFF); pr_info("out-of-bounds in strncpy_from_user()\n"); - unused = strncpy_from_user(kmem, usermem, size + 1); + unused = strncpy_from_user(kmem, usermem, size + 1
Re: [PATCH v2] kasan: fix KASAN unit tests for tag-based KASAN
On Mon, 2020-07-06 at 08:19 +0200, Dmitry Vyukov wrote: > On Mon, Jul 6, 2020 at 4:21 AM Walter Wu wrote: > > > > We use tag-based KASAN, then KASAN unit tests don't detect out-of-bounds > > memory access. They need to be fixed. > > > > With tag-based KASAN, the state of each 16 aligned bytes of memory is > > encoded in one shadow byte and the shadow value is tag of pointer, so > > we need to read next shadow byte, the shadow value is not equal to tag > > value of pointer, so that tag-based KASAN will detect out-of-bounds > > memory access. > > > > Signed-off-by: Walter Wu > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Matthias Brugger > > Cc: Andrey Konovalov > > Cc: Andrew Morton > > --- > > > > changes since v1: > > - Reduce amount of non-compiled code. > > - KUnit-KASAN Integration patchset are not merged yet. My patch should > > have conflict with it, if needed, we can continue to wait it. > > > > --- > > > > lib/test_kasan.c | 81 ++-- > > 1 file changed, 64 insertions(+), 17 deletions(-) > > > > diff --git a/lib/test_kasan.c b/lib/test_kasan.c > > index e3087d90e00d..660664439d52 100644 > > --- a/lib/test_kasan.c > > +++ b/lib/test_kasan.c > > @@ -40,7 +40,11 @@ static noinline void __init kmalloc_oob_right(void) > > return; > > } > > > > - ptr[size] = 'x'; > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + ptr[size] = 'x'; > > + else > > + ptr[size + 5] = 'x'; > > + > > Hi Walter, > > Would if be possible to introduce something like: > > #define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : 8) > It is good suggestion. Thanks. > and then add it throughout as > > ptr[size + OOB_TAG_OFF] = 'x'; > > ? > The current version results in quite some amount of additional code > that needs to be read, extended and maintained in the future. So I am > thinking if it's possible to minimize it somehow... > Ok, I will send next patch by your suggestion. Thanks. > > kfree(ptr); > > } > > > > @@ -92,7 +96,11 @@ static noinline void __init > > kmalloc_pagealloc_oob_right(void) > > return; > > } > > > > - ptr[size] = 0; > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + ptr[size] = 0; > > + else > > + ptr[size + 6] = 0; > > + > > kfree(ptr); > > } > > > > @@ -162,7 +170,11 @@ static noinline void __init > > kmalloc_oob_krealloc_more(void) > > return; > > } > > > > - ptr2[size2] = 'x'; > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + ptr2[size2] = 'x'; > > + else > > + ptr2[size2 + 13] = 'x'; > > + > > kfree(ptr2); > > } > > > > @@ -180,7 +192,12 @@ static noinline void __init > > kmalloc_oob_krealloc_less(void) > > kfree(ptr1); > > return; > > } > > - ptr2[size2] = 'x'; > > + > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + ptr2[size2] = 'x'; > > + else > > + ptr2[size2 + 2] = 'x'; > > + > > kfree(ptr2); > > } > > > > @@ -216,7 +233,11 @@ static noinline void __init kmalloc_oob_memset_2(void) > > return; > > } > > > > - memset(ptr+7, 0, 2); > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + memset(ptr+7, 0, 2); > > + else > > + memset(ptr+15, 0, 2); > > + > > kfree(ptr); > > } > > > > @@ -232,7 +253,11 @@ static noinline void __init kmalloc_oob_memset_4(void) > > return; > > } > > > > - memset(ptr+5, 0, 4); > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + memset(ptr+5, 0, 4); > > + else > > + memset(ptr+15, 0, 4); > > + > > kfree(ptr); > > } > > > > @@ -249,7 +274,11 @@ static noinline void __init kmalloc_oob_memset_8(void) > > return; > > } > > > > - memset(ptr+1, 0, 8); > > + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) > > + memset(ptr+1, 0, 8); > > + else > > + memset(ptr+1
[PATCH v2] kasan: fix KASAN unit tests for tag-based KASAN
We use tag-based KASAN, then KASAN unit tests don't detect out-of-bounds memory access. They need to be fixed. With tag-based KASAN, the state of each 16 aligned bytes of memory is encoded in one shadow byte and the shadow value is tag of pointer, so we need to read next shadow byte, the shadow value is not equal to tag value of pointer, so that tag-based KASAN will detect out-of-bounds memory access. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger Cc: Andrey Konovalov Cc: Andrew Morton --- changes since v1: - Reduce amount of non-compiled code. - KUnit-KASAN Integration patchset are not merged yet. My patch should have conflict with it, if needed, we can continue to wait it. --- lib/test_kasan.c | 81 ++-- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..660664439d52 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -40,7 +40,11 @@ static noinline void __init kmalloc_oob_right(void) return; } - ptr[size] = 'x'; + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + ptr[size] = 'x'; + else + ptr[size + 5] = 'x'; + kfree(ptr); } @@ -92,7 +96,11 @@ static noinline void __init kmalloc_pagealloc_oob_right(void) return; } - ptr[size] = 0; + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + ptr[size] = 0; + else + ptr[size + 6] = 0; + kfree(ptr); } @@ -162,7 +170,11 @@ static noinline void __init kmalloc_oob_krealloc_more(void) return; } - ptr2[size2] = 'x'; + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + ptr2[size2] = 'x'; + else + ptr2[size2 + 13] = 'x'; + kfree(ptr2); } @@ -180,7 +192,12 @@ static noinline void __init kmalloc_oob_krealloc_less(void) kfree(ptr1); return; } - ptr2[size2] = 'x'; + + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + ptr2[size2] = 'x'; + else + ptr2[size2 + 2] = 'x'; + kfree(ptr2); } @@ -216,7 +233,11 @@ static noinline void __init kmalloc_oob_memset_2(void) return; } - memset(ptr+7, 0, 2); + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + memset(ptr+7, 0, 2); + else + memset(ptr+15, 0, 2); + kfree(ptr); } @@ -232,7 +253,11 @@ static noinline void __init kmalloc_oob_memset_4(void) return; } - memset(ptr+5, 0, 4); + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + memset(ptr+5, 0, 4); + else + memset(ptr+15, 0, 4); + kfree(ptr); } @@ -249,7 +274,11 @@ static noinline void __init kmalloc_oob_memset_8(void) return; } - memset(ptr+1, 0, 8); + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + memset(ptr+1, 0, 8); + else + memset(ptr+15, 0, 8); + kfree(ptr); } @@ -265,7 +294,11 @@ static noinline void __init kmalloc_oob_memset_16(void) return; } - memset(ptr+1, 0, 16); + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + memset(ptr+1, 0, 16); + else + memset(ptr+15, 0, 16); + kfree(ptr); } @@ -281,7 +314,11 @@ static noinline void __init kmalloc_oob_in_memset(void) return; } - memset(ptr, 0, size+5); + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + memset(ptr, 0, size+5); + else + memset(ptr, 0, size+7); + kfree(ptr); } @@ -415,7 +452,11 @@ static noinline void __init kmem_cache_oob(void) return; } - *p = p[size]; + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + *p = p[size]; + else + *p = p[size + 8]; + kmem_cache_free(cache, p); kmem_cache_destroy(cache); } @@ -497,6 +538,7 @@ static noinline void __init copy_user_test(void) char __user *usermem; size_t size = 10; int unused; + size_t oob_size; kmem = kmalloc(size, GFP_KERNEL); if (!kmem) @@ -511,26 +553,31 @@ static noinline void __init copy_user_test(void) return; } + if (IS_ENABLED(CONFIG_KASAN_GENERIC)) + oob_size = 1; + else + oob_size = 7; + pr_info("out-of-bounds in copy_from_user()\n"); - unused = copy_from_user(kmem, usermem, size + 1); + unused = copy_from_user(kmem, usermem, size + oob_size); pr_info("out-of-bounds in copy_to_user()\n"); - unused = copy_to_user(usermem, kmem, size + 1); + unused = copy_to_user(usermem, kmem, size + oob_size); pr_info("out-of-bounds in __copy_from_u
Re: [PATCH v7 0/4] kasan: memorize and print call_rcu stack
On Mon, 2020-06-01 at 13:08 +0800, Walter Wu wrote: > This patchset improves KASAN reports by making them to have > call_rcu() call stack information. It is useful for programmers > to solve use-after-free or double-free memory issue. > > The KASAN report was as follows(cleaned up slightly): > > BUG: KASAN: use-after-free in kasan_rcu_reclaim+0x58/0x60 > > Freed by task 0: > kasan_save_stack+0x24/0x50 > kasan_set_track+0x24/0x38 > kasan_set_free_info+0x18/0x20 > __kasan_slab_free+0x10c/0x170 > kasan_slab_free+0x10/0x18 > kfree+0x98/0x270 > kasan_rcu_reclaim+0x1c/0x60 > > Last call_rcu(): > kasan_save_stack+0x24/0x50 > kasan_record_aux_stack+0xbc/0xd0 > call_rcu+0x8c/0x580 > kasan_rcu_uaf+0xf4/0xf8 > > Generic KASAN will record the last two call_rcu() call stacks and > print up to 2 call_rcu() call stacks in KASAN report. it is only > suitable for generic KASAN. > > This feature considers the size of struct kasan_alloc_meta and > kasan_free_meta, we try to optimize the structure layout and size > , lets it get better memory consumption. > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ > > Changes since v1: > - remove new config option, default enable it in generic KASAN > - test this feature in SLAB/SLUB, it is pass. > - modify macro to be more clearly > - modify documentation > > Changes since v2: > - change recording from first/last to the last two call stacks > - move free track into kasan free meta > - init slab_free_meta on object slot creation > - modify documentation > > Changes since v3: > - change variable name to be more clearly > - remove the redundant condition > - remove init free meta-data and increasing object condition > > Changes since v4: > - add a macro KASAN_KMALLOC_FREETRACK in order to check whether > print free stack > - change printing message > - remove descriptions in Kocong.kasan > > Changes since v5: > - reuse print_stack() in print_track() > > Changes since v6: > - fix typo > - renamed the variable name in testcase > > Walter Wu (4): > rcu: kasan: record and print call_rcu() call stack > kasan: record and print the free track > kasan: add tests for call_rcu stack recording > kasan: update documentation for generic kasan > Hi Andrew, Would you tell me why don't pick up this patches? Do I miss something? I will want to implement another new patches, but it need to depend on this patches. Thanks for your helps. Walter > Documentation/dev-tools/kasan.rst | 3 +++ > include/linux/kasan.h | 2 ++ > kernel/rcu/tree.c | 2 ++ > lib/test_kasan.c | 30 ++ > mm/kasan/common.c | 26 -- > mm/kasan/generic.c| 43 > +++ > mm/kasan/generic_report.c | 1 + > mm/kasan/kasan.h | 23 +-- > mm/kasan/quarantine.c | 1 + > mm/kasan/report.c | 54 > +++--- > mm/kasan/tags.c | 37 + > 11 files changed, 171 insertions(+), 51 deletions(-)
[PATCH v7 4/4] kasan: update documentation for generic kasan
Generic KASAN will support to record the last two call_rcu() call stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c652d740735d..fede42e6536b 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,6 +193,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. +Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one +and the second to last. + Software tag-based KASAN -- 2.18.0
[PATCH v7 3/4] kasan: add tests for call_rcu stack recording
Test call_rcu() call stack recording and verify whether it correctly is printed in KASAN report. Signed-off-by: Walter Wu Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Matthias Brugger --- Changes since v6: - renamed the variable name in testcase --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..19c72c1501ef 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -792,6 +792,35 @@ static noinline void __init vmalloc_oob(void) static void __init vmalloc_oob(void) {} #endif +static struct kasan_rcu_info { + int i; + struct rcu_head rcu; +} *global_rcu_ptr; + +static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp) +{ + struct kasan_rcu_info *fp = container_of(rp, + struct kasan_rcu_info, rcu); + + kfree(fp); + fp->i = 1; +} + +static noinline void __init kasan_rcu_uaf(void) +{ + struct kasan_rcu_info *ptr; + + pr_info("use-after-free in kasan_rcu_reclaim\n"); + ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + global_rcu_ptr = rcu_dereference_protected(ptr, NULL); + call_rcu(_rcu_ptr->rcu, kasan_rcu_reclaim); +} + static int __init kmalloc_tests_init(void) { /* @@ -839,6 +868,7 @@ static int __init kmalloc_tests_init(void) kasan_bitops(); kmalloc_double_kzfree(); vmalloc_oob(); + kasan_rcu_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v7 2/4] kasan: record and print the free track
Move free track from kasan_alloc_meta to kasan_free_meta in order to make struct kasan_alloc_meta and kasan_free_meta size are both 16 bytes. It is a good size because it is the minimal redzone size and a good number of alignment. For free track, we make some modifications as shown below: 1) Remove the free_track from struct kasan_alloc_meta. 2) Add the free_track into struct kasan_free_meta. 3) Add a macro KASAN_KMALLOC_FREETRACK in order to check whether it can print free stack in KASAN report. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Co-developed-by: Dmitry Vyukov Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko --- mm/kasan/common.c | 22 ++ mm/kasan/generic.c| 22 ++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 13 +++-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 26 -- mm/kasan/tags.c | 37 + 7 files changed, 78 insertions(+), 44 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 8bc618289bb1..47b53912f322 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) return stack_depot_save(entries, nr_entries, flags); } -static inline void set_track(struct kasan_track *track, gfp_t flags) +void kasan_set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; track->stack = kasan_save_stack(flags); @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, return (void *)object + cache->kasan_info.free_meta_offset; } - -static void kasan_set_free_info(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - u8 idx = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - idx = alloc_meta->free_track_idx; - alloc_meta->free_pointer_tag[idx] = tag; - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; -#endif - - set_track(_meta->free_track[idx], GFP_NOWAIT); -} - void kasan_poison_slab(struct page *page) { unsigned long i; @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_KMALLOC_REDZONE); if (cache->flags & SLAB_KASAN) - set_track(_alloc_info(cache, object)->alloc_track, flags); + kasan_set_track(_alloc_info(cache, object)->alloc_track, flags); return set_tag(object, tag); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 8acf48882ba2..4b3cbad7431b 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -346,3 +346,25 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } + +void kasan_set_free_info(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + kasan_set_track(_meta->free_track, GFP_NOWAIT); + + /* +* the object was freed and has free track set +*/ + *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK; +} + +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag) +{ + if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK) + return NULL; + return _free_info(cache, object)->free_track; +} diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c index e200acb2d292..a38c7a9e192a 100644 --- a/mm/kasan/generic_report.c +++ b/mm/kasan/generic_report.c @@ -80,6 +80,7 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) break; case KASAN_FREE_PAGE: case KASAN_KMALLOC_FREE: + case KASAN_KMALLOC_FREETRACK: bug_type = "use-after-free"; break; case KASAN_ALLOCA_LEFT: diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index a7391bc83070..ef655a1c6e15 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -17,15 +17,17 @@ #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 */ #else #define KASAN_FREE_PAGE KASAN_TAG_INVALID #define KASAN_PAGE_REDZONE KASAN_TAG_INVALID #define KASAN_KMALLOC_REDZONE KASAN_TAG_INVAL
[PATCH v7 1/4] rcu: kasan: record and print call_rcu() call stack
This feature will record the last two call_rcu() call stacks and prints up to 2 call_rcu() call stacks in KASAN report. When call_rcu() is called, we store the call_rcu() call stack into slub alloc meta-data, so that the KASAN report can print rcu stack. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Acked-by: Paul E. McKenney Reviewed-and-tested-by: Dmitry Vyukov Reviewed-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Alexander Potapenko Cc: Andrew Morton Cc: Josh Triplett Cc: Mathieu Desnoyers Cc: Lai Jiangshan Cc: Joel Fernandes --- Changes since v6: - fix typo --- include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ mm/kasan/common.c | 4 ++-- mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 10 ++ mm/kasan/report.c | 28 +++- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 31314ca7c635..23b7ee00572d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); +void kasan_record_aux_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} +static inline void kasan_record_aux_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 06548e2ebb72..36a4ff7f320b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "../time/tick-internal.h" #include "tree.h" @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) head->func = func; head->next = NULL; local_irq_save(flags); + kasan_record_aux_stack(head); rdp = this_cpu_ptr(_data); /* Add the callback to our list. */ diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 2906358e42f0..8bc618289bb1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -41,7 +41,7 @@ #include "kasan.h" #include "../slab.h" -static inline depot_stack_handle_t save_stack(gfp_t flags) +depot_stack_handle_t kasan_save_stack(gfp_t flags) { unsigned long entries[KASAN_STACK_DEPTH]; unsigned int nr_entries; @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) static inline void set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; - track->stack = save_stack(flags); + track->stack = kasan_save_stack(flags); } void kasan_enable_current(void) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 56ff8885fe2e..8acf48882ba2 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); DEFINE_ASAN_SET_SHADOW(f3); DEFINE_ASAN_SET_SHADOW(f5); DEFINE_ASAN_SET_SHADOW(f8); + +void kasan_record_aux_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two call_rcu() call stacks. +*/ + alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e8f37199d885..a7391bc83070 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -104,7 +104,15 @@ struct kasan_track { struct kasan_alloc_meta { struct kasan_track alloc_track; +#ifdef CONFIG_KASAN_GENERIC + /* +* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The free stack is stored into struct kasan_free_meta. +*/ + depot_stack_handle_t aux_stack[2]; +#else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; +#endif #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY u8 free_pointer_tag[KASAN_NR_FREE_STACKS]; u8 free_track_idx; @@ -159,6 +167,8 @@ void kasan_report_invalid_free(void *object, unsigned long ip); struct page *kasan_addr_to_page(const void *addr); +depot_stack_handle_t kasan_save_stack(gfp_t flags); + #if defined(CONFIG_KASAN_GENERIC) && \ (defined(CONFIG_SLAB) || defined(CONFIG_SLUB)) void quarantine_put(struct kasan_free_met
[PATCH v7 0/4] kasan: memorize and print call_rcu stack
This patchset improves KASAN reports by making them to have call_rcu() call stack information. It is useful for programmers to solve use-after-free or double-free memory issue. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_rcu_reclaim+0x58/0x60 Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x18/0x20 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_rcu_reclaim+0x1c/0x60 Last call_rcu(): kasan_save_stack+0x24/0x50 kasan_record_aux_stack+0xbc/0xd0 call_rcu+0x8c/0x580 kasan_rcu_uaf+0xf4/0xf8 Generic KASAN will record the last two call_rcu() call stacks and print up to 2 call_rcu() call stacks in KASAN report. it is only suitable for generic KASAN. This feature considers the size of struct kasan_alloc_meta and kasan_free_meta, we try to optimize the structure layout and size , lets it get better memory consumption. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Changes since v1: - remove new config option, default enable it in generic KASAN - test this feature in SLAB/SLUB, it is pass. - modify macro to be more clearly - modify documentation Changes since v2: - change recording from first/last to the last two call stacks - move free track into kasan free meta - init slab_free_meta on object slot creation - modify documentation Changes since v3: - change variable name to be more clearly - remove the redundant condition - remove init free meta-data and increasing object condition Changes since v4: - add a macro KASAN_KMALLOC_FREETRACK in order to check whether print free stack - change printing message - remove descriptions in Kocong.kasan Changes since v5: - reuse print_stack() in print_track() Changes since v6: - fix typo - renamed the variable name in testcase Walter Wu (4): rcu: kasan: record and print call_rcu() call stack kasan: record and print the free track kasan: add tests for call_rcu stack recording kasan: update documentation for generic kasan Documentation/dev-tools/kasan.rst | 3 +++ include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ lib/test_kasan.c | 30 ++ mm/kasan/common.c | 26 -- mm/kasan/generic.c| 43 +++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 23 +-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 54 +++--- mm/kasan/tags.c | 37 + 11 files changed, 171 insertions(+), 51 deletions(-)
Re: [PATCH v6 1/4] rcu/kasan: record and print call_rcu() call stack
On Mon, 2020-05-25 at 11:56 +0200, Dmitry Vyukov wrote: > On Fri, May 22, 2020 at 4:01 AM Walter Wu wrote: > > > > This feature will record the last two call_rcu() call stacks and > > prints up to 2 call_rcu() call stacks in KASAN report. > > > > When call_rcu() is called, we store the call_rcu() call stack into > > slub alloc meta-data, so that the KASAN report can print rcu stack. > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ > > Hi Walter, > > The series look good to me. Thanks for bearing with me. I am eager to > see this in syzbot reports. > > Reviewed-and-tested-by: Dmitry Vyukov > Hi Dmitry, I appreciate for your response. This patches make KASAN report more better and let me learn a lot. Thank you for good suggestion and detailed explanation. Walter > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Acked-by: Paul E. McKenney > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > Cc: Josh Triplett > > Cc: Mathieu Desnoyers > > Cc: Lai Jiangshan > > Cc: Joel Fernandes > > Cc: Andrey Konovalov > > --- > > include/linux/kasan.h | 2 ++ > > kernel/rcu/tree.c | 2 ++ > > mm/kasan/common.c | 4 ++-- > > mm/kasan/generic.c| 21 + > > mm/kasan/kasan.h | 10 ++ > > mm/kasan/report.c | 28 +++- > > 6 files changed, 60 insertions(+), 7 deletions(-) > > > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 31314ca7c635..23b7ee00572d 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct > > kmem_cache *cache) { return 0; } > > > > void kasan_cache_shrink(struct kmem_cache *cache); > > void kasan_cache_shutdown(struct kmem_cache *cache); > > +void kasan_record_aux_stack(void *ptr); > > > > #else /* CONFIG_KASAN_GENERIC */ > > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > +static inline void kasan_record_aux_stack(void *ptr) {} > > > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c > > index 06548e2ebb72..36a4ff7f320b 100644 > > --- a/kernel/rcu/tree.c > > +++ b/kernel/rcu/tree.c > > @@ -57,6 +57,7 @@ > > #include > > #include > > #include > > +#include > > #include "../time/tick-internal.h" > > > > #include "tree.h" > > @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) > > head->func = func; > > head->next = NULL; > > local_irq_save(flags); > > + kasan_record_aux_stack(head); > > rdp = this_cpu_ptr(_data); > > > > /* Add the callback to our list. */ > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 2906358e42f0..8bc618289bb1 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -41,7 +41,7 @@ > > #include "kasan.h" > > #include "../slab.h" > > > > -static inline depot_stack_handle_t save_stack(gfp_t flags) > > +depot_stack_handle_t kasan_save_stack(gfp_t flags) > > { > > unsigned long entries[KASAN_STACK_DEPTH]; > > unsigned int nr_entries; > > @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) > > static inline void set_track(struct kasan_track *track, gfp_t flags) > > { > > track->pid = current->pid; > > - track->stack = save_stack(flags); > > + track->stack = kasan_save_stack(flags); > > } > > > > void kasan_enable_current(void) > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 56ff8885fe2e..8acf48882ba2 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); > > DEFINE_ASAN_SET_SHADOW(f3); > > DEFINE_ASAN_SET_SHADOW(f5); > > DEFINE_ASAN_SET_SHADOW(f8); > > + > > +void kasan_record_aux_stack(void *addr) > > +{ > > + struct page *page = kasan_addr_to_page(addr); > > + struct kmem_cache *cache; > > + struct kasan_alloc_meta *alloc_info; > &g
[PATCH v6 3/4] kasan: add tests for call_rcu stack recording
Test call_rcu() call stack recording and verify whether it correctly is printed in KASAN report. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..6e5fb05d42d8 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -792,6 +792,35 @@ static noinline void __init vmalloc_oob(void) static void __init vmalloc_oob(void) {} #endif +static struct kasan_rcu_info { + int i; + struct rcu_head rcu; +} *global_ptr; + +static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp) +{ + struct kasan_rcu_info *fp = container_of(rp, + struct kasan_rcu_info, rcu); + + kfree(fp); + fp->i = 1; +} + +static noinline void __init kasan_rcu_uaf(void) +{ + struct kasan_rcu_info *ptr; + + pr_info("use-after-free in kasan_rcu_reclaim\n"); + ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + global_ptr = rcu_dereference_protected(ptr, NULL); + call_rcu(_ptr->rcu, kasan_rcu_reclaim); +} + static int __init kmalloc_tests_init(void) { /* @@ -839,6 +868,7 @@ static int __init kmalloc_tests_init(void) kasan_bitops(); kmalloc_double_kzfree(); vmalloc_oob(); + kasan_rcu_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v6 2/4] kasan: record and print the free track
Move free track from kasan_alloc_meta to kasan_free_meta in order to make struct kasan_alloc_meta and kasan_free_meta size are both 16 bytes. It is a good size because it is the minimal redzone size and a good number of alignment. For free track, we make some modifications as shown below: 1) Remove the free_track from struct kasan_alloc_meta. 2) Add the free_track into struct kasan_free_meta. 3) Add a macro KASAN_KMALLOC_FREETRACK in order to check whether it can print free stack in KASAN report. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Co-developed-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko --- mm/kasan/common.c | 22 ++ mm/kasan/generic.c| 22 ++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 13 +++-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 26 -- mm/kasan/tags.c | 37 + 7 files changed, 78 insertions(+), 44 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 8bc618289bb1..47b53912f322 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) return stack_depot_save(entries, nr_entries, flags); } -static inline void set_track(struct kasan_track *track, gfp_t flags) +void kasan_set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; track->stack = kasan_save_stack(flags); @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, return (void *)object + cache->kasan_info.free_meta_offset; } - -static void kasan_set_free_info(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - u8 idx = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - idx = alloc_meta->free_track_idx; - alloc_meta->free_pointer_tag[idx] = tag; - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; -#endif - - set_track(_meta->free_track[idx], GFP_NOWAIT); -} - void kasan_poison_slab(struct page *page) { unsigned long i; @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_KMALLOC_REDZONE); if (cache->flags & SLAB_KASAN) - set_track(_alloc_info(cache, object)->alloc_track, flags); + kasan_set_track(_alloc_info(cache, object)->alloc_track, flags); return set_tag(object, tag); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 8acf48882ba2..4b3cbad7431b 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -346,3 +346,25 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } + +void kasan_set_free_info(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + kasan_set_track(_meta->free_track, GFP_NOWAIT); + + /* +* the object was freed and has free track set +*/ + *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK; +} + +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag) +{ + if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK) + return NULL; + return _free_info(cache, object)->free_track; +} diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c index e200acb2d292..a38c7a9e192a 100644 --- a/mm/kasan/generic_report.c +++ b/mm/kasan/generic_report.c @@ -80,6 +80,7 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) break; case KASAN_FREE_PAGE: case KASAN_KMALLOC_FREE: + case KASAN_KMALLOC_FREETRACK: bug_type = "use-after-free"; break; case KASAN_ALLOCA_LEFT: diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index a7391bc83070..ef655a1c6e15 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -17,15 +17,17 @@ #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 */ #else #define KASAN_FREE_PAGE KASAN_TAG_INVALID #define KASAN_PAGE_REDZONE KASAN_TAG_INVALID #define KASAN_KMALLOC_REDZONE KASAN_TAG_INVALID #define KASAN_KMALLOC_FREE KASAN_TAG_INVA
[PATCH v6 4/4] kasan: update documentation for generic kasan
Generic KASAN will support to record the last two call_rcu() call stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c652d740735d..fede42e6536b 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,6 +193,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. +Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one +and the second to last. + Software tag-based KASAN -- 2.18.0
[PATCH v6 1/4] rcu/kasan: record and print call_rcu() call stack
This feature will record the last two call_rcu() call stacks and prints up to 2 call_rcu() call stacks in KASAN report. When call_rcu() is called, we store the call_rcu() call stack into slub alloc meta-data, so that the KASAN report can print rcu stack. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Acked-by: Paul E. McKenney Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Josh Triplett Cc: Mathieu Desnoyers Cc: Lai Jiangshan Cc: Joel Fernandes Cc: Andrey Konovalov --- include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ mm/kasan/common.c | 4 ++-- mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 10 ++ mm/kasan/report.c | 28 +++- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 31314ca7c635..23b7ee00572d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); +void kasan_record_aux_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} +static inline void kasan_record_aux_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 06548e2ebb72..36a4ff7f320b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "../time/tick-internal.h" #include "tree.h" @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) head->func = func; head->next = NULL; local_irq_save(flags); + kasan_record_aux_stack(head); rdp = this_cpu_ptr(_data); /* Add the callback to our list. */ diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 2906358e42f0..8bc618289bb1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -41,7 +41,7 @@ #include "kasan.h" #include "../slab.h" -static inline depot_stack_handle_t save_stack(gfp_t flags) +depot_stack_handle_t kasan_save_stack(gfp_t flags) { unsigned long entries[KASAN_STACK_DEPTH]; unsigned int nr_entries; @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) static inline void set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; - track->stack = save_stack(flags); + track->stack = kasan_save_stack(flags); } void kasan_enable_current(void) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 56ff8885fe2e..8acf48882ba2 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); DEFINE_ASAN_SET_SHADOW(f3); DEFINE_ASAN_SET_SHADOW(f5); DEFINE_ASAN_SET_SHADOW(f8); + +void kasan_record_aux_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two call_rcu() call stacks. +*/ + alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e8f37199d885..a7391bc83070 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -104,7 +104,15 @@ struct kasan_track { struct kasan_alloc_meta { struct kasan_track alloc_track; +#ifdef CONFIG_KASAN_GENERIC + /* +* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The free stack is stored into struct kasan_free_meta. +*/ + depot_stack_handle_t aux_stack[2]; +#else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; +#endif #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY u8 free_pointer_tag[KASAN_NR_FREE_STACKS]; u8 free_track_idx; @@ -159,6 +167,8 @@ void kasan_report_invalid_free(void *object, unsigned long ip); struct page *kasan_addr_to_page(const void *addr); +depot_stack_handle_t kasan_save_stack(gfp_t flags); + #if defined(CONFIG_KASAN_GENERIC) && \ (defined(CONFIG_SLAB) || defined(CONFIG_SLUB)) void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache); diff --git a/mm/kasan/report
[PATCH v6 0/4] kasan: memorize and print call_rcu stack
This patchset improves KASAN reports by making them to have call_rcu() call stack information. It is useful for programmers to solve use-after-free or double-free memory issue. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_rcu_reclaim+0x58/0x60 Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x18/0x20 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_rcu_reclaim+0x1c/0x60 Last call_rcu(): kasan_save_stack+0x24/0x50 kasan_record_aux_stack+0xbc/0xd0 call_rcu+0x8c/0x580 kasan_rcu_uaf+0xf4/0xf8 Generic KASAN will record the last two call_rcu() call stacks and print up to 2 call_rcu() call stacks in KASAN report. it is only suitable for generic KASAN. This feature considers the size of struct kasan_alloc_meta and kasan_free_meta, we try to optimize the structure layout and size , let it get better memory consumption. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Changes since v2: - remove new config option, default enable it in generic KASAN - test this feature in SLAB/SLUB, it is pass. - modify macro to be more clearly - modify documentation Changes since v3: - change recording from first/last to the last two call stacks - move free track into kasan free meta - init slab_free_meta on object slot creation - modify documentation Changes since v4: - change variable name to be more clearly - remove the redundant condition - remove init free meta-data and increasing object condition Changes since v5: - add a macro KASAN_KMALLOC_FREETRACK in order to check whether print free stack - change printing message - remove descriptions in Kocong.kasan Changes since v6: - reuse print_stack() in print_track() Walter Wu (4): rcu/kasan: record and print call_rcu() call stack kasan: record and print the free track kasan: add tests for call_rcu stack recording kasan: update documentation for generic kasan Documentation/dev-tools/kasan.rst | 3 +++ include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ lib/test_kasan.c | 30 ++ mm/kasan/common.c | 26 -- mm/kasan/generic.c| 43 +++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 23 +-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 54 +++--- mm/kasan/tags.c | 37 + 11 files changed, 171 insertions(+), 51 deletions(-)
Re: [PATCH v5 1/4] rcu/kasan: record and print call_rcu() call stack
> On Wed, May 20, 2020 at 2:34 PM Walter Wu wrote: > > > > This feature will record the last two call_rcu() call stacks and > > prints up to 2 call_rcu() call stacks in KASAN report. > > > > When call_rcu() is called, we store the call_rcu() call stack into > > slub alloc meta-data, so that the KASAN report can print rcu stack. > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Acked-by: Paul E. McKenney > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > Cc: Josh Triplett > > Cc: Mathieu Desnoyers > > Cc: Lai Jiangshan > > Cc: Joel Fernandes > > Cc: Andrey Konovalov > > --- > > include/linux/kasan.h | 2 ++ > > kernel/rcu/tree.c | 2 ++ > > mm/kasan/common.c | 4 ++-- > > mm/kasan/generic.c| 21 + > > mm/kasan/kasan.h | 10 ++ > > mm/kasan/report.c | 24 > > 6 files changed, 61 insertions(+), 2 deletions(-) > > > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 31314ca7c635..23b7ee00572d 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct > > kmem_cache *cache) { return 0; } > > > > void kasan_cache_shrink(struct kmem_cache *cache); > > void kasan_cache_shutdown(struct kmem_cache *cache); > > +void kasan_record_aux_stack(void *ptr); > > > > #else /* CONFIG_KASAN_GENERIC */ > > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > +static inline void kasan_record_aux_stack(void *ptr) {} > > > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c > > index 06548e2ebb72..36a4ff7f320b 100644 > > --- a/kernel/rcu/tree.c > > +++ b/kernel/rcu/tree.c > > @@ -57,6 +57,7 @@ > > #include > > #include > > #include > > +#include > > #include "../time/tick-internal.h" > > > > #include "tree.h" > > @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) > > head->func = func; > > head->next = NULL; > > local_irq_save(flags); > > + kasan_record_aux_stack(head); > > rdp = this_cpu_ptr(_data); > > > > /* Add the callback to our list. */ > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 2906358e42f0..8bc618289bb1 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -41,7 +41,7 @@ > > #include "kasan.h" > > #include "../slab.h" > > > > -static inline depot_stack_handle_t save_stack(gfp_t flags) > > +depot_stack_handle_t kasan_save_stack(gfp_t flags) > > { > > unsigned long entries[KASAN_STACK_DEPTH]; > > unsigned int nr_entries; > > @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) > > static inline void set_track(struct kasan_track *track, gfp_t flags) > > { > > track->pid = current->pid; > > - track->stack = save_stack(flags); > > + track->stack = kasan_save_stack(flags); > > } > > > > void kasan_enable_current(void) > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 56ff8885fe2e..8acf48882ba2 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); > > DEFINE_ASAN_SET_SHADOW(f3); > > DEFINE_ASAN_SET_SHADOW(f5); > > DEFINE_ASAN_SET_SHADOW(f8); > > + > > +void kasan_record_aux_stack(void *addr) > > +{ > > + struct page *page = kasan_addr_to_page(addr); > > + struct kmem_cache *cache; > > + struct kasan_alloc_meta *alloc_info; > > + void *object; > > + > > + if (!(page && PageSlab(page))) > > + return; > > + > > + cache = page->slab_cache; > > + object = nearest_obj(cache, page, addr); > > + alloc_info = get_alloc_info(cache, object); > > + > > + /* > > +* record the last two call_rcu() call stacks. > > +
[PATCH v5 4/4] kasan: update documentation for generic kasan
Generic KASAN will support to record the last two call_rcu() call stacks and print them in KASAN report. So that need to update documentation. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c652d740735d..fede42e6536b 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,6 +193,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. +Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one +and the second to last. + Software tag-based KASAN -- 2.18.0
[PATCH v5 3/4] kasan: add tests for call_rcu stack recording
Test call_rcu() call stack recording and verify whether it correctly is printed in KASAN report. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..6e5fb05d42d8 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -792,6 +792,35 @@ static noinline void __init vmalloc_oob(void) static void __init vmalloc_oob(void) {} #endif +static struct kasan_rcu_info { + int i; + struct rcu_head rcu; +} *global_ptr; + +static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp) +{ + struct kasan_rcu_info *fp = container_of(rp, + struct kasan_rcu_info, rcu); + + kfree(fp); + fp->i = 1; +} + +static noinline void __init kasan_rcu_uaf(void) +{ + struct kasan_rcu_info *ptr; + + pr_info("use-after-free in kasan_rcu_reclaim\n"); + ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + global_ptr = rcu_dereference_protected(ptr, NULL); + call_rcu(_ptr->rcu, kasan_rcu_reclaim); +} + static int __init kmalloc_tests_init(void) { /* @@ -839,6 +868,7 @@ static int __init kmalloc_tests_init(void) kasan_bitops(); kmalloc_double_kzfree(); vmalloc_oob(); + kasan_rcu_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v5 2/4] kasan: record and print the free track
Move free track from kasan_alloc_meta to kasan_free_meta in order to make struct kasan_alloc_meta and kasan_free_meta size are both 16 bytes. It is a good size because it is the minimal redzone size and a good number of alignment. For free track, we make some modifications as shown below: 1) Remove the free_track from struct kasan_alloc_meta. 2) Add the free_track into struct kasan_free_meta. 3) Add a macro KASAN_KMALLOC_FREETRACK in order to check whether print free stack in KASAN report. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Co-developed-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko --- mm/kasan/common.c | 22 ++ mm/kasan/generic.c| 22 ++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 13 +++-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 26 -- mm/kasan/tags.c | 37 + 7 files changed, 78 insertions(+), 44 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 8bc618289bb1..47b53912f322 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) return stack_depot_save(entries, nr_entries, flags); } -static inline void set_track(struct kasan_track *track, gfp_t flags) +void kasan_set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; track->stack = kasan_save_stack(flags); @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, return (void *)object + cache->kasan_info.free_meta_offset; } - -static void kasan_set_free_info(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - u8 idx = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - idx = alloc_meta->free_track_idx; - alloc_meta->free_pointer_tag[idx] = tag; - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; -#endif - - set_track(_meta->free_track[idx], GFP_NOWAIT); -} - void kasan_poison_slab(struct page *page) { unsigned long i; @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_KMALLOC_REDZONE); if (cache->flags & SLAB_KASAN) - set_track(_alloc_info(cache, object)->alloc_track, flags); + kasan_set_track(_alloc_info(cache, object)->alloc_track, flags); return set_tag(object, tag); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 8acf48882ba2..4b3cbad7431b 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -346,3 +346,25 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } + +void kasan_set_free_info(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + kasan_set_track(_meta->free_track, GFP_NOWAIT); + + /* +* the object was freed and has free track set +*/ + *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK; +} + +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag) +{ + if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK) + return NULL; + return _free_info(cache, object)->free_track; +} diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c index e200acb2d292..a38c7a9e192a 100644 --- a/mm/kasan/generic_report.c +++ b/mm/kasan/generic_report.c @@ -80,6 +80,7 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) break; case KASAN_FREE_PAGE: case KASAN_KMALLOC_FREE: + case KASAN_KMALLOC_FREETRACK: bug_type = "use-after-free"; break; case KASAN_ALLOCA_LEFT: diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index a7391bc83070..ef655a1c6e15 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -17,15 +17,17 @@ #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 */ #else #define KASAN_FREE_PAGE KASAN_TAG_INVALID #define KASAN_PAGE_REDZONE KASAN_TAG_INVALID #define KASAN_KMALLOC_REDZONE KASAN_TAG_INVALID #define KASAN_KMALLOC_FREE KASAN_TAG_INVALID +#defin
[PATCH v5 1/4] rcu/kasan: record and print call_rcu() call stack
This feature will record the last two call_rcu() call stacks and prints up to 2 call_rcu() call stacks in KASAN report. When call_rcu() is called, we store the call_rcu() call stack into slub alloc meta-data, so that the KASAN report can print rcu stack. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Acked-by: Paul E. McKenney Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Josh Triplett Cc: Mathieu Desnoyers Cc: Lai Jiangshan Cc: Joel Fernandes Cc: Andrey Konovalov --- include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ mm/kasan/common.c | 4 ++-- mm/kasan/generic.c| 21 + mm/kasan/kasan.h | 10 ++ mm/kasan/report.c | 24 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 31314ca7c635..23b7ee00572d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); +void kasan_record_aux_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} +static inline void kasan_record_aux_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 06548e2ebb72..36a4ff7f320b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "../time/tick-internal.h" #include "tree.h" @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) head->func = func; head->next = NULL; local_irq_save(flags); + kasan_record_aux_stack(head); rdp = this_cpu_ptr(_data); /* Add the callback to our list. */ diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 2906358e42f0..8bc618289bb1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -41,7 +41,7 @@ #include "kasan.h" #include "../slab.h" -static inline depot_stack_handle_t save_stack(gfp_t flags) +depot_stack_handle_t kasan_save_stack(gfp_t flags) { unsigned long entries[KASAN_STACK_DEPTH]; unsigned int nr_entries; @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) static inline void set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; - track->stack = save_stack(flags); + track->stack = kasan_save_stack(flags); } void kasan_enable_current(void) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 56ff8885fe2e..8acf48882ba2 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -325,3 +325,24 @@ DEFINE_ASAN_SET_SHADOW(f2); DEFINE_ASAN_SET_SHADOW(f3); DEFINE_ASAN_SET_SHADOW(f5); DEFINE_ASAN_SET_SHADOW(f8); + +void kasan_record_aux_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* +* record the last two call_rcu() call stacks. +*/ + alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e8f37199d885..a7391bc83070 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -104,7 +104,15 @@ struct kasan_track { struct kasan_alloc_meta { struct kasan_track alloc_track; +#ifdef CONFIG_KASAN_GENERIC + /* +* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The free stack is stored into struct kasan_free_meta. +*/ + depot_stack_handle_t aux_stack[2]; +#else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; +#endif #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY u8 free_pointer_tag[KASAN_NR_FREE_STACKS]; u8 free_track_idx; @@ -159,6 +167,8 @@ void kasan_report_invalid_free(void *object, unsigned long ip); struct page *kasan_addr_to_page(const void *addr); +depot_stack_handle_t kasan_save_stack(gfp_t flags); + #if defined(CONFIG_KASAN_GENERIC) && \ (defined(CONFIG_SLAB) || defined(CONFIG_SLUB)) void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache); diff --git a/mm/kasan/report.c b/m
[PATCH v5 0/4] kasan: memorize and print call_rcu stack
This patchset improves KASAN reports by making them to have call_rcu() call stack information. It is useful for programmers to solve use-after-free or double-free memory issue. The KASAN report was as follows(cleaned up slightly): BUG: KASAN: use-after-free in kasan_rcu_reclaim+0x58/0x60 Freed by task 0: kasan_save_stack+0x24/0x50 kasan_set_track+0x24/0x38 kasan_set_free_info+0x18/0x20 __kasan_slab_free+0x10c/0x170 kasan_slab_free+0x10/0x18 kfree+0x98/0x270 kasan_rcu_reclaim+0x1c/0x60 Last one call_rcu() call stack: kasan_save_stack+0x24/0x50 kasan_record_aux_stack+0xbc/0xd0 call_rcu+0x8c/0x580 kasan_rcu_uaf+0xf4/0xf8 Generic KASAN will record the last two call_rcu() call stacks and print up to 2 call_rcu() call stacks in KASAN report. it is only suitable for generic KASAN. This feature considers the size of struct kasan_alloc_meta and kasan_free_meta, we try to optimize the structure layout and size , let it get better memory consumption. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Changes since v2: - remove new config option, default enable it in generic KASAN - test this feature in SLAB/SLUB, it is pass. - modify macro to be more clearly - modify documentation Changes since v3: - change recording from first/last to the last two call stacks - move free track into kasan free meta - init slab_free_meta on object slot creation - modify documentation Changes since v4: - change variable name to be more clearly - remove the redundant condition - remove init free meta-data and increasing object condition Changes since v5: - add a macro KASAN_KMALLOC_FREETRACK in order to check whether print free stack - change printing message - remove descriptions in Kocong.kasan Walter Wu (4): rcu/kasan: record and print call_rcu() call stack kasan: record and print the free track kasan: add tests for call_rcu stack recording kasan: update documentation for generic kasan Documentation/dev-tools/kasan.rst | 3 +++ include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ lib/test_kasan.c | 30 ++ mm/kasan/common.c | 26 -- mm/kasan/generic.c| 43 +++ mm/kasan/generic_report.c | 1 + mm/kasan/kasan.h | 23 +-- mm/kasan/quarantine.c | 1 + mm/kasan/report.c | 50 -- mm/kasan/tags.c | 37 + 11 files changed, 172 insertions(+), 46 deletions(-)
Re: [PATCH v4 2/4] kasan: record and print the free track
On Wed, 2020-05-20 at 13:15 +0200, 'Dmitry Vyukov' via kasan-dev wrote: > On Wed, May 20, 2020 at 12:15 PM Walter Wu wrote: > > > > On Wed, 2020-05-20 at 11:44 +0200, 'Dmitry Vyukov' via kasan-dev wrote: > > > On Wed, May 20, 2020 at 11:17 AM Walter Wu > > > wrote: > > > > > > On Wed, 2020-05-20 at 13:14 +0800, Walter Wu wrote: > > > > > > > > On Wed, May 20, 2020 at 6:03 AM Walter Wu > > > > > > > > wrote: > > > > > > > > > > > > > > > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > > > > > > > > wrote: > > > > > > > > > > > > > > > > > > > > > > Move free track from slub alloc meta-data to slub free > > > > > > > > > > > meta-data in > > > > > > > > > > > order to make struct kasan_free_meta size is 16 bytes. It > > > > > > > > > > > is a good > > > > > > > > > > > size because it is the minimal redzone size and a good > > > > > > > > > > > number of > > > > > > > > > > > alignment. > > > > > > > > > > > > > > > > > > > > > > For free track in generic KASAN, we do the modification > > > > > > > > > > > in struct > > > > > > > > > > > kasan_alloc_meta and kasan_free_meta: > > > > > > > > > > > - remove free track from kasan_alloc_meta. > > > > > > > > > > > - add free track into kasan_free_meta. > > > > > > > > > > > > > > > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > > > > > > > > > > > > > > > Signed-off-by: Walter Wu > > > > > > > > > > > Suggested-by: Dmitry Vyukov > > > > > > > > > > > Cc: Andrey Ryabinin > > > > > > > > > > > Cc: Dmitry Vyukov > > > > > > > > > > > Cc: Alexander Potapenko > > > > > > > > > > > --- > > > > > > > > > > > mm/kasan/common.c | 22 ++ > > > > > > > > > > > mm/kasan/generic.c | 18 ++ > > > > > > > > > > > mm/kasan/kasan.h | 7 +++ > > > > > > > > > > > mm/kasan/report.c | 20 > > > > > > > > > > > mm/kasan/tags.c| 37 > > > > > > > > > > > + > > > > > > > > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > > > > > > > > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > > > > > > > > index 8bc618289bb1..47b53912f322 100644 > > > > > > > > > > > --- a/mm/kasan/common.c > > > > > > > > > > > +++ b/mm/kasan/common.c > > > > > > > > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t > > > > > > > > > > > kasan_save_stack(gfp_t flags) > > > > > > > > > > > return stack_depot_save(entries, nr_entries, > > > > > > > > > > > flags); > > > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > > > -static inline void set_track(struct kasan_track *track, > > > > > > > > > > > gfp_t flags) > > > > > > > > > > > +void kasan_set_track(struct kasan_track *track, gfp_t > > > > > > > > > > > flags) > > > > > > > > > > > { > > > > > > > > > > > track->pid = current->pid; > > > > > > > > > > > track->stack = kasan_save_stack(flags); > > > > > > > > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta > > > > > > > > > > > *get_free_info(struct kmem_cache *cache, > > > > > > > > > > > return (void *)o
Re: [PATCH v4 2/4] kasan: record and print the free track
On Wed, 2020-05-20 at 11:44 +0200, 'Dmitry Vyukov' via kasan-dev wrote: > On Wed, May 20, 2020 at 11:17 AM Walter Wu wrote: > > > > On Wed, 2020-05-20 at 13:14 +0800, Walter Wu wrote: > > > > > > On Wed, May 20, 2020 at 6:03 AM Walter Wu > > > > > > wrote: > > > > > > > > > > > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > > > > > > wrote: > > > > > > > > > > > > > > > > > > Move free track from slub alloc meta-data to slub free > > > > > > > > > meta-data in > > > > > > > > > order to make struct kasan_free_meta size is 16 bytes. It is > > > > > > > > > a good > > > > > > > > > size because it is the minimal redzone size and a good number > > > > > > > > > of > > > > > > > > > alignment. > > > > > > > > > > > > > > > > > > For free track in generic KASAN, we do the modification in > > > > > > > > > struct > > > > > > > > > kasan_alloc_meta and kasan_free_meta: > > > > > > > > > - remove free track from kasan_alloc_meta. > > > > > > > > > - add free track into kasan_free_meta. > > > > > > > > > > > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > > > > > > > > > > > Signed-off-by: Walter Wu > > > > > > > > > Suggested-by: Dmitry Vyukov > > > > > > > > > Cc: Andrey Ryabinin > > > > > > > > > Cc: Dmitry Vyukov > > > > > > > > > Cc: Alexander Potapenko > > > > > > > > > --- > > > > > > > > > mm/kasan/common.c | 22 ++ > > > > > > > > > mm/kasan/generic.c | 18 ++ > > > > > > > > > mm/kasan/kasan.h | 7 +++ > > > > > > > > > mm/kasan/report.c | 20 > > > > > > > > > mm/kasan/tags.c| 37 + > > > > > > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > > > > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > > > > > > index 8bc618289bb1..47b53912f322 100644 > > > > > > > > > --- a/mm/kasan/common.c > > > > > > > > > +++ b/mm/kasan/common.c > > > > > > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t > > > > > > > > > flags) > > > > > > > > > return stack_depot_save(entries, nr_entries, flags); > > > > > > > > > } > > > > > > > > > > > > > > > > > > -static inline void set_track(struct kasan_track *track, > > > > > > > > > gfp_t flags) > > > > > > > > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > > > > > > > > { > > > > > > > > > track->pid = current->pid; > > > > > > > > > track->stack = kasan_save_stack(flags); > > > > > > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta > > > > > > > > > *get_free_info(struct kmem_cache *cache, > > > > > > > > > return (void *)object + > > > > > > > > > cache->kasan_info.free_meta_offset; > > > > > > > > > } > > > > > > > > > > > > > > > > > > - > > > > > > > > > -static void kasan_set_free_info(struct kmem_cache *cache, > > > > > > > > > - void *object, u8 tag) > > > > > > > > > -{ > > > > > > > > > - struct kasan_alloc_meta *alloc_meta; > > > > > > > > > - u8 idx = 0; > > > > > > > > > - > > > > > > > > > - alloc_meta = get_alloc_info(cache, object); > > > > > > > > > - > > > > > > > > > -#ifdef CONFIG_KASAN_SW_
Re: [PATCH v4 2/4] kasan: record and print the free track
> On Wed, May 20, 2020 at 8:18 AM Walter Wu wrote: > > > > On Wed, 2020-05-20 at 13:14 +0800, Walter Wu wrote: > > > > On Wed, May 20, 2020 at 6:03 AM Walter Wu > > > > wrote: > > > > > > > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > > > > wrote: > > > > > > > > > > > > > > Move free track from slub alloc meta-data to slub free meta-data > > > > > > > in > > > > > > > order to make struct kasan_free_meta size is 16 bytes. It is a > > > > > > > good > > > > > > > size because it is the minimal redzone size and a good number of > > > > > > > alignment. > > > > > > > > > > > > > > For free track in generic KASAN, we do the modification in struct > > > > > > > kasan_alloc_meta and kasan_free_meta: > > > > > > > - remove free track from kasan_alloc_meta. > > > > > > > - add free track into kasan_free_meta. > > > > > > > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > > > > > > > Signed-off-by: Walter Wu > > > > > > > Suggested-by: Dmitry Vyukov > > > > > > > Cc: Andrey Ryabinin > > > > > > > Cc: Dmitry Vyukov > > > > > > > Cc: Alexander Potapenko > > > > > > > --- > > > > > > > mm/kasan/common.c | 22 ++ > > > > > > > mm/kasan/generic.c | 18 ++ > > > > > > > mm/kasan/kasan.h | 7 +++ > > > > > > > mm/kasan/report.c | 20 > > > > > > > mm/kasan/tags.c| 37 + > > > > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > > > > index 8bc618289bb1..47b53912f322 100644 > > > > > > > --- a/mm/kasan/common.c > > > > > > > +++ b/mm/kasan/common.c > > > > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t > > > > > > > flags) > > > > > > > return stack_depot_save(entries, nr_entries, flags); > > > > > > > } > > > > > > > > > > > > > > -static inline void set_track(struct kasan_track *track, gfp_t > > > > > > > flags) > > > > > > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > > > > > > { > > > > > > > track->pid = current->pid; > > > > > > > track->stack = kasan_save_stack(flags); > > > > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct > > > > > > > kmem_cache *cache, > > > > > > > return (void *)object + > > > > > > > cache->kasan_info.free_meta_offset; > > > > > > > } > > > > > > > > > > > > > > - > > > > > > > -static void kasan_set_free_info(struct kmem_cache *cache, > > > > > > > - void *object, u8 tag) > > > > > > > -{ > > > > > > > - struct kasan_alloc_meta *alloc_meta; > > > > > > > - u8 idx = 0; > > > > > > > - > > > > > > > - alloc_meta = get_alloc_info(cache, object); > > > > > > > - > > > > > > > -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY > > > > > > > - idx = alloc_meta->free_track_idx; > > > > > > > - alloc_meta->free_pointer_tag[idx] = tag; > > > > > > > - alloc_meta->free_track_idx = (idx + 1) % > > > > > > > KASAN_NR_FREE_STACKS; > > > > > > > -#endif > > > > > > > - > > > > > > > - set_track(_meta->free_track[idx], GFP_NOWAIT); > > > > > > > -} > > > > > > > - > > > > > > > void kasan_poison_slab(struct page *page) > > > > > > > { > > > > > > > unsigned long i; > > > > >
Re: [PATCH v4 2/4] kasan: record and print the free track
On Wed, 2020-05-20 at 13:14 +0800, Walter Wu wrote: > > On Wed, May 20, 2020 at 6:03 AM Walter Wu wrote: > > > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > > wrote: > > > > > > > > > > Move free track from slub alloc meta-data to slub free meta-data in > > > > > order to make struct kasan_free_meta size is 16 bytes. It is a good > > > > > size because it is the minimal redzone size and a good number of > > > > > alignment. > > > > > > > > > > For free track in generic KASAN, we do the modification in struct > > > > > kasan_alloc_meta and kasan_free_meta: > > > > > - remove free track from kasan_alloc_meta. > > > > > - add free track into kasan_free_meta. > > > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > > > Signed-off-by: Walter Wu > > > > > Suggested-by: Dmitry Vyukov > > > > > Cc: Andrey Ryabinin > > > > > Cc: Dmitry Vyukov > > > > > Cc: Alexander Potapenko > > > > > --- > > > > > mm/kasan/common.c | 22 ++ > > > > > mm/kasan/generic.c | 18 ++ > > > > > mm/kasan/kasan.h | 7 +++ > > > > > mm/kasan/report.c | 20 > > > > > mm/kasan/tags.c| 37 + > > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > > index 8bc618289bb1..47b53912f322 100644 > > > > > --- a/mm/kasan/common.c > > > > > +++ b/mm/kasan/common.c > > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) > > > > > return stack_depot_save(entries, nr_entries, flags); > > > > > } > > > > > > > > > > -static inline void set_track(struct kasan_track *track, gfp_t flags) > > > > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > > > > { > > > > > track->pid = current->pid; > > > > > track->stack = kasan_save_stack(flags); > > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct > > > > > kmem_cache *cache, > > > > > return (void *)object + cache->kasan_info.free_meta_offset; > > > > > } > > > > > > > > > > - > > > > > -static void kasan_set_free_info(struct kmem_cache *cache, > > > > > - void *object, u8 tag) > > > > > -{ > > > > > - struct kasan_alloc_meta *alloc_meta; > > > > > - u8 idx = 0; > > > > > - > > > > > - alloc_meta = get_alloc_info(cache, object); > > > > > - > > > > > -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY > > > > > - idx = alloc_meta->free_track_idx; > > > > > - alloc_meta->free_pointer_tag[idx] = tag; > > > > > - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; > > > > > -#endif > > > > > - > > > > > - set_track(_meta->free_track[idx], GFP_NOWAIT); > > > > > -} > > > > > - > > > > > void kasan_poison_slab(struct page *page) > > > > > { > > > > > unsigned long i; > > > > > @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache > > > > > *cache, const void *object, > > > > > KASAN_KMALLOC_REDZONE); > > > > > > > > > > if (cache->flags & SLAB_KASAN) > > > > > - set_track(_alloc_info(cache, > > > > > object)->alloc_track, flags); > > > > > + kasan_set_track(_alloc_info(cache, > > > > > object)->alloc_track, flags); > > > > > > > > > > return set_tag(object, tag); > > > > > } > > > > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > > > > index 3372bdcaf92a..763d8a13e0ac 100644 > > > > > --- a/mm/kasan/generic.c > > > > > +++ b/mm/kasan/generic.c > > > > > @@ -344,3 +344,21 @@ void kasan_record_aux_stack(void *addr) > > > > > alloc_info
Re: [PATCH v4 2/4] kasan: record and print the free track
> On Wed, May 20, 2020 at 6:03 AM Walter Wu wrote: > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > wrote: > > > > > > > > Move free track from slub alloc meta-data to slub free meta-data in > > > > order to make struct kasan_free_meta size is 16 bytes. It is a good > > > > size because it is the minimal redzone size and a good number of > > > > alignment. > > > > > > > > For free track in generic KASAN, we do the modification in struct > > > > kasan_alloc_meta and kasan_free_meta: > > > > - remove free track from kasan_alloc_meta. > > > > - add free track into kasan_free_meta. > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > Signed-off-by: Walter Wu > > > > Suggested-by: Dmitry Vyukov > > > > Cc: Andrey Ryabinin > > > > Cc: Dmitry Vyukov > > > > Cc: Alexander Potapenko > > > > --- > > > > mm/kasan/common.c | 22 ++ > > > > mm/kasan/generic.c | 18 ++ > > > > mm/kasan/kasan.h | 7 +++ > > > > mm/kasan/report.c | 20 > > > > mm/kasan/tags.c| 37 + > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > index 8bc618289bb1..47b53912f322 100644 > > > > --- a/mm/kasan/common.c > > > > +++ b/mm/kasan/common.c > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) > > > > return stack_depot_save(entries, nr_entries, flags); > > > > } > > > > > > > > -static inline void set_track(struct kasan_track *track, gfp_t flags) > > > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > > > { > > > > track->pid = current->pid; > > > > track->stack = kasan_save_stack(flags); > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct > > > > kmem_cache *cache, > > > > return (void *)object + cache->kasan_info.free_meta_offset; > > > > } > > > > > > > > - > > > > -static void kasan_set_free_info(struct kmem_cache *cache, > > > > - void *object, u8 tag) > > > > -{ > > > > - struct kasan_alloc_meta *alloc_meta; > > > > - u8 idx = 0; > > > > - > > > > - alloc_meta = get_alloc_info(cache, object); > > > > - > > > > -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY > > > > - idx = alloc_meta->free_track_idx; > > > > - alloc_meta->free_pointer_tag[idx] = tag; > > > > - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; > > > > -#endif > > > > - > > > > - set_track(_meta->free_track[idx], GFP_NOWAIT); > > > > -} > > > > - > > > > void kasan_poison_slab(struct page *page) > > > > { > > > > unsigned long i; > > > > @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache > > > > *cache, const void *object, > > > > KASAN_KMALLOC_REDZONE); > > > > > > > > if (cache->flags & SLAB_KASAN) > > > > - set_track(_alloc_info(cache, object)->alloc_track, > > > > flags); > > > > + kasan_set_track(_alloc_info(cache, > > > > object)->alloc_track, flags); > > > > > > > > return set_tag(object, tag); > > > > } > > > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > > > index 3372bdcaf92a..763d8a13e0ac 100644 > > > > --- a/mm/kasan/generic.c > > > > +++ b/mm/kasan/generic.c > > > > @@ -344,3 +344,21 @@ void kasan_record_aux_stack(void *addr) > > > > alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; > > > > alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); > > > > } > > > > + > > > > +void kasan_set_free_info(struct kmem_cache *cache, > > > > + void *object, u8 tag) > > > > +{ > > > > + struct kasan_free_meta *free_meta; > > > > + > > > >
Re: [PATCH v4 2/4] kasan: record and print the free track
> On Wed, May 20, 2020 at 6:03 AM Walter Wu wrote: > > > > > On Tue, May 19, 2020 at 4:25 AM Walter Wu > > > wrote: > > > > > > > > Move free track from slub alloc meta-data to slub free meta-data in > > > > order to make struct kasan_free_meta size is 16 bytes. It is a good > > > > size because it is the minimal redzone size and a good number of > > > > alignment. > > > > > > > > For free track in generic KASAN, we do the modification in struct > > > > kasan_alloc_meta and kasan_free_meta: > > > > - remove free track from kasan_alloc_meta. > > > > - add free track into kasan_free_meta. > > > > > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > > > > > Signed-off-by: Walter Wu > > > > Suggested-by: Dmitry Vyukov > > > > Cc: Andrey Ryabinin > > > > Cc: Dmitry Vyukov > > > > Cc: Alexander Potapenko > > > > --- > > > > mm/kasan/common.c | 22 ++ > > > > mm/kasan/generic.c | 18 ++ > > > > mm/kasan/kasan.h | 7 +++ > > > > mm/kasan/report.c | 20 > > > > mm/kasan/tags.c| 37 + > > > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > > > index 8bc618289bb1..47b53912f322 100644 > > > > --- a/mm/kasan/common.c > > > > +++ b/mm/kasan/common.c > > > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) > > > > return stack_depot_save(entries, nr_entries, flags); > > > > } > > > > > > > > -static inline void set_track(struct kasan_track *track, gfp_t flags) > > > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > > > { > > > > track->pid = current->pid; > > > > track->stack = kasan_save_stack(flags); > > > > @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct > > > > kmem_cache *cache, > > > > return (void *)object + cache->kasan_info.free_meta_offset; > > > > } > > > > > > > > - > > > > -static void kasan_set_free_info(struct kmem_cache *cache, > > > > - void *object, u8 tag) > > > > -{ > > > > - struct kasan_alloc_meta *alloc_meta; > > > > - u8 idx = 0; > > > > - > > > > - alloc_meta = get_alloc_info(cache, object); > > > > - > > > > -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY > > > > - idx = alloc_meta->free_track_idx; > > > > - alloc_meta->free_pointer_tag[idx] = tag; > > > > - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; > > > > -#endif > > > > - > > > > - set_track(_meta->free_track[idx], GFP_NOWAIT); > > > > -} > > > > - > > > > void kasan_poison_slab(struct page *page) > > > > { > > > > unsigned long i; > > > > @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache > > > > *cache, const void *object, > > > > KASAN_KMALLOC_REDZONE); > > > > > > > > if (cache->flags & SLAB_KASAN) > > > > - set_track(_alloc_info(cache, object)->alloc_track, > > > > flags); > > > > + kasan_set_track(_alloc_info(cache, > > > > object)->alloc_track, flags); > > > > > > > > return set_tag(object, tag); > > > > } > > > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > > > index 3372bdcaf92a..763d8a13e0ac 100644 > > > > --- a/mm/kasan/generic.c > > > > +++ b/mm/kasan/generic.c > > > > @@ -344,3 +344,21 @@ void kasan_record_aux_stack(void *addr) > > > > alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; > > > > alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); > > > > } > > > > + > > > > +void kasan_set_free_info(struct kmem_cache *cache, > > > > + void *object, u8 tag) > > > > +{ > > > > + struct kasan_free_meta *free_meta; > > > > + > > > >
Re: [PATCH v4 2/4] kasan: record and print the free track
> On Tue, May 19, 2020 at 4:25 AM Walter Wu wrote: > > > > Move free track from slub alloc meta-data to slub free meta-data in > > order to make struct kasan_free_meta size is 16 bytes. It is a good > > size because it is the minimal redzone size and a good number of > > alignment. > > > > For free track in generic KASAN, we do the modification in struct > > kasan_alloc_meta and kasan_free_meta: > > - remove free track from kasan_alloc_meta. > > - add free track into kasan_free_meta. > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > --- > > mm/kasan/common.c | 22 ++ > > mm/kasan/generic.c | 18 ++ > > mm/kasan/kasan.h | 7 +++ > > mm/kasan/report.c | 20 > > mm/kasan/tags.c| 37 + > > 5 files changed, 64 insertions(+), 40 deletions(-) > > > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 8bc618289bb1..47b53912f322 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) > > return stack_depot_save(entries, nr_entries, flags); > > } > > > > -static inline void set_track(struct kasan_track *track, gfp_t flags) > > +void kasan_set_track(struct kasan_track *track, gfp_t flags) > > { > > track->pid = current->pid; > > track->stack = kasan_save_stack(flags); > > @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct > > kmem_cache *cache, > > return (void *)object + cache->kasan_info.free_meta_offset; > > } > > > > - > > -static void kasan_set_free_info(struct kmem_cache *cache, > > - void *object, u8 tag) > > -{ > > - struct kasan_alloc_meta *alloc_meta; > > - u8 idx = 0; > > - > > - alloc_meta = get_alloc_info(cache, object); > > - > > -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY > > - idx = alloc_meta->free_track_idx; > > - alloc_meta->free_pointer_tag[idx] = tag; > > - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; > > -#endif > > - > > - set_track(_meta->free_track[idx], GFP_NOWAIT); > > -} > > - > > void kasan_poison_slab(struct page *page) > > { > > unsigned long i; > > @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, > > const void *object, > > KASAN_KMALLOC_REDZONE); > > > > if (cache->flags & SLAB_KASAN) > > - set_track(_alloc_info(cache, object)->alloc_track, > > flags); > > + kasan_set_track(_alloc_info(cache, > > object)->alloc_track, flags); > > > > return set_tag(object, tag); > > } > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 3372bdcaf92a..763d8a13e0ac 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -344,3 +344,21 @@ void kasan_record_aux_stack(void *addr) > > alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; > > alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); > > } > > + > > +void kasan_set_free_info(struct kmem_cache *cache, > > + void *object, u8 tag) > > +{ > > + struct kasan_free_meta *free_meta; > > + > > + free_meta = get_free_info(cache, object); > > + kasan_set_track(_meta->free_track, GFP_NOWAIT); > > +} > > + > > +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, > > + void *object, u8 tag) > > +{ > > + struct kasan_free_meta *free_meta; > > + > > + free_meta = get_free_info(cache, object); > > + return _meta->free_track; > > +} > > diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h > > index a7391bc83070..ad897ec36545 100644 > > --- a/mm/kasan/kasan.h > > +++ b/mm/kasan/kasan.h > > @@ -127,6 +127,9 @@ struct kasan_free_meta { > > * Otherwise it might be used for the allocator freelist. > > */ > > struct qlist_node quarantine_link; > > +#ifdef CONFIG_KASAN_GENERIC > > + struct kasan_track free_track; > > +#endif > > }; > > > > struct kasan_alloc_meta *get_a
Re: [PATCH v4 1/4] rcu/kasan: record and print call_rcu() call stack
On Tue, 2020-05-19 at 08:48 -0700, Paul E. McKenney wrote: > On Tue, May 19, 2020 at 10:23:59AM +0800, Walter Wu wrote: > > This feature will record the last two call_rcu() call stacks and > > prints up to 2 call_rcu() call stacks in KASAN report. > > > > When call_rcu() is called, we store the call_rcu() call stack into > > slub alloc meta-data, so that the KASAN report can print rcu stack. > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > Cc: Paul E. McKenney > > Cc: Josh Triplett > > Cc: Mathieu Desnoyers > > Cc: Lai Jiangshan > > Cc: Joel Fernandes > > From an RCU perspective: > > Acked-by: Paul E. McKenney > Hi Paul, Thank you for your suggestion and review. Walter > > --- > > include/linux/kasan.h | 2 ++ > > kernel/rcu/tree.c | 2 ++ > > lib/Kconfig.kasan | 2 ++ > > mm/kasan/common.c | 4 ++-- > > mm/kasan/generic.c| 19 +++ > > mm/kasan/kasan.h | 10 ++ > > mm/kasan/report.c | 24 > > 7 files changed, 61 insertions(+), 2 deletions(-) > > > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 31314ca7c635..23b7ee00572d 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct > > kmem_cache *cache) { return 0; } > > > > void kasan_cache_shrink(struct kmem_cache *cache); > > void kasan_cache_shutdown(struct kmem_cache *cache); > > +void kasan_record_aux_stack(void *ptr); > > > > #else /* CONFIG_KASAN_GENERIC */ > > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > +static inline void kasan_record_aux_stack(void *ptr) {} > > > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c > > index 06548e2ebb72..36a4ff7f320b 100644 > > --- a/kernel/rcu/tree.c > > +++ b/kernel/rcu/tree.c > > @@ -57,6 +57,7 @@ > > #include > > #include > > #include > > +#include > > #include "../time/tick-internal.h" > > > > #include "tree.h" > > @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) > > head->func = func; > > head->next = NULL; > > local_irq_save(flags); > > + kasan_record_aux_stack(head); > > rdp = this_cpu_ptr(_data); > > > > /* Add the callback to our list. */ > > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > > index 81f5464ea9e1..4e83cf6e3caa 100644 > > --- a/lib/Kconfig.kasan > > +++ b/lib/Kconfig.kasan > > @@ -58,6 +58,8 @@ config KASAN_GENERIC > > For better error detection enable CONFIG_STACKTRACE. > > Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB > > (the resulting kernel does not boot). > > + In generic mode KASAN prints the last two call_rcu() call stacks in > > + reports. > > > > config KASAN_SW_TAGS > > bool "Software tag-based mode" > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 2906358e42f0..8bc618289bb1 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -41,7 +41,7 @@ > > #include "kasan.h" > > #include "../slab.h" > > > > -static inline depot_stack_handle_t save_stack(gfp_t flags) > > +depot_stack_handle_t kasan_save_stack(gfp_t flags) > > { > > unsigned long entries[KASAN_STACK_DEPTH]; > > unsigned int nr_entries; > > @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) > > static inline void set_track(struct kasan_track *track, gfp_t flags) > > { > > track->pid = current->pid; > > - track->stack = save_stack(flags); > > + track->stack = kasan_save_stack(flags); > > } > > > > void kasan_enable_current(void) > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 56ff8885fe2e..3372bdcaf92a 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -325,3 +325,22
Re: [PATCH v4 1/4] rcu/kasan: record and print call_rcu() call stack
Hi Andrey, On Tue, 2020-05-19 at 16:52 +0200, 'Andrey Konovalov' via kasan-dev wrote: > On Tue, May 19, 2020 at 4:24 AM Walter Wu wrote: > > > > This feature will record the last two call_rcu() call stacks and > > prints up to 2 call_rcu() call stacks in KASAN report. > > > > When call_rcu() is called, we store the call_rcu() call stack into > > slub alloc meta-data, so that the KASAN report can print rcu stack. > > > > [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 > > [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ > > > > Signed-off-by: Walter Wu > > Suggested-by: Dmitry Vyukov > > Cc: Andrey Ryabinin > > Cc: Dmitry Vyukov > > Cc: Alexander Potapenko > > Cc: Andrew Morton > > Cc: Paul E. McKenney > > Cc: Josh Triplett > > Cc: Mathieu Desnoyers > > Cc: Lai Jiangshan > > Cc: Joel Fernandes > > --- > > include/linux/kasan.h | 2 ++ > > kernel/rcu/tree.c | 2 ++ > > lib/Kconfig.kasan | 2 ++ > > mm/kasan/common.c | 4 ++-- > > mm/kasan/generic.c| 19 +++ > > mm/kasan/kasan.h | 10 ++ > > mm/kasan/report.c | 24 > > 7 files changed, 61 insertions(+), 2 deletions(-) > > > > diff --git a/include/linux/kasan.h b/include/linux/kasan.h > > index 31314ca7c635..23b7ee00572d 100644 > > --- a/include/linux/kasan.h > > +++ b/include/linux/kasan.h > > @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct > > kmem_cache *cache) { return 0; } > > > > void kasan_cache_shrink(struct kmem_cache *cache); > > void kasan_cache_shutdown(struct kmem_cache *cache); > > +void kasan_record_aux_stack(void *ptr); > > > > #else /* CONFIG_KASAN_GENERIC */ > > > > static inline void kasan_cache_shrink(struct kmem_cache *cache) {} > > static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} > > +static inline void kasan_record_aux_stack(void *ptr) {} > > > > #endif /* CONFIG_KASAN_GENERIC */ > > > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c > > index 06548e2ebb72..36a4ff7f320b 100644 > > --- a/kernel/rcu/tree.c > > +++ b/kernel/rcu/tree.c > > @@ -57,6 +57,7 @@ > > #include > > #include > > #include > > +#include > > #include "../time/tick-internal.h" > > > > #include "tree.h" > > @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) > > head->func = func; > > head->next = NULL; > > local_irq_save(flags); > > + kasan_record_aux_stack(head); > > rdp = this_cpu_ptr(_data); > > > > /* Add the callback to our list. */ > > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > > index 81f5464ea9e1..4e83cf6e3caa 100644 > > --- a/lib/Kconfig.kasan > > +++ b/lib/Kconfig.kasan > > @@ -58,6 +58,8 @@ config KASAN_GENERIC > > For better error detection enable CONFIG_STACKTRACE. > > Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB > > (the resulting kernel does not boot). > > + In generic mode KASAN prints the last two call_rcu() call stacks > > in > > + reports. > > I don't think we need this here, mentioning this in the documentation is fine. > Ok, we will remove it. Only mention it in the documentation. > > > > > config KASAN_SW_TAGS > > bool "Software tag-based mode" > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > > index 2906358e42f0..8bc618289bb1 100644 > > --- a/mm/kasan/common.c > > +++ b/mm/kasan/common.c > > @@ -41,7 +41,7 @@ > > #include "kasan.h" > > #include "../slab.h" > > > > -static inline depot_stack_handle_t save_stack(gfp_t flags) > > +depot_stack_handle_t kasan_save_stack(gfp_t flags) > > { > > unsigned long entries[KASAN_STACK_DEPTH]; > > unsigned int nr_entries; > > @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) > > static inline void set_track(struct kasan_track *track, gfp_t flags) > > { > > track->pid = current->pid; > > - track->stack = save_stack(flags); > > + track->stack = kasan_save_stack(flags); > > } > > > > void kasan_enable_current(void) > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index 56ff8885fe2e..3372bdcaf92a 100644 &
[PATCH v4 3/4] kasan: add tests for call_rcu stack recording
Test call_rcu() call stack recording and verify whether it correctly is printed in KASAN report. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Matthias Brugger --- lib/test_kasan.c | 30 ++ 1 file changed, 30 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index e3087d90e00d..6e5fb05d42d8 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -792,6 +792,35 @@ static noinline void __init vmalloc_oob(void) static void __init vmalloc_oob(void) {} #endif +static struct kasan_rcu_info { + int i; + struct rcu_head rcu; +} *global_ptr; + +static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp) +{ + struct kasan_rcu_info *fp = container_of(rp, + struct kasan_rcu_info, rcu); + + kfree(fp); + fp->i = 1; +} + +static noinline void __init kasan_rcu_uaf(void) +{ + struct kasan_rcu_info *ptr; + + pr_info("use-after-free in kasan_rcu_reclaim\n"); + ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL); + if (!ptr) { + pr_err("Allocation failed\n"); + return; + } + + global_ptr = rcu_dereference_protected(ptr, NULL); + call_rcu(_ptr->rcu, kasan_rcu_reclaim); +} + static int __init kmalloc_tests_init(void) { /* @@ -839,6 +868,7 @@ static int __init kmalloc_tests_init(void) kasan_bitops(); kmalloc_double_kzfree(); vmalloc_oob(); + kasan_rcu_uaf(); kasan_restore_multi_shot(multishot); -- 2.18.0
[PATCH v4 4/4] kasan: update documentation for generic kasan
Generic KASAN will support to record the last two call_rcu() call stacks and print them in KASAN report. So need to update documentation. Signed-off-by: Walter Wu Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jonathan Corbet --- Documentation/dev-tools/kasan.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index c652d740735d..fede42e6536b 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -193,6 +193,9 @@ function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel. +Generic KASAN prints up to 2 call_rcu() call stacks in reports, the last one +and the second to last. + Software tag-based KASAN -- 2.18.0
[PATCH v4 2/4] kasan: record and print the free track
Move free track from slub alloc meta-data to slub free meta-data in order to make struct kasan_free_meta size is 16 bytes. It is a good size because it is the minimal redzone size and a good number of alignment. For free track in generic KASAN, we do the modification in struct kasan_alloc_meta and kasan_free_meta: - remove free track from kasan_alloc_meta. - add free track into kasan_free_meta. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko --- mm/kasan/common.c | 22 ++ mm/kasan/generic.c | 18 ++ mm/kasan/kasan.h | 7 +++ mm/kasan/report.c | 20 mm/kasan/tags.c| 37 + 5 files changed, 64 insertions(+), 40 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 8bc618289bb1..47b53912f322 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -51,7 +51,7 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags) return stack_depot_save(entries, nr_entries, flags); } -static inline void set_track(struct kasan_track *track, gfp_t flags) +void kasan_set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; track->stack = kasan_save_stack(flags); @@ -299,24 +299,6 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, return (void *)object + cache->kasan_info.free_meta_offset; } - -static void kasan_set_free_info(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - u8 idx = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - idx = alloc_meta->free_track_idx; - alloc_meta->free_pointer_tag[idx] = tag; - alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS; -#endif - - set_track(_meta->free_track[idx], GFP_NOWAIT); -} - void kasan_poison_slab(struct page *page) { unsigned long i; @@ -492,7 +474,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_KMALLOC_REDZONE); if (cache->flags & SLAB_KASAN) - set_track(_alloc_info(cache, object)->alloc_track, flags); + kasan_set_track(_alloc_info(cache, object)->alloc_track, flags); return set_tag(object, tag); } diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 3372bdcaf92a..763d8a13e0ac 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -344,3 +344,21 @@ void kasan_record_aux_stack(void *addr) alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); } + +void kasan_set_free_info(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + kasan_set_track(_meta->free_track, GFP_NOWAIT); +} + +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag) +{ + struct kasan_free_meta *free_meta; + + free_meta = get_free_info(cache, object); + return _meta->free_track; +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index a7391bc83070..ad897ec36545 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -127,6 +127,9 @@ struct kasan_free_meta { * Otherwise it might be used for the allocator freelist. */ struct qlist_node quarantine_link; +#ifdef CONFIG_KASAN_GENERIC + struct kasan_track free_track; +#endif }; struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache, @@ -168,6 +171,10 @@ void kasan_report_invalid_free(void *object, unsigned long ip); struct page *kasan_addr_to_page(const void *addr); depot_stack_handle_t kasan_save_stack(gfp_t flags); +void kasan_set_track(struct kasan_track *track, gfp_t flags); +void kasan_set_free_info(struct kmem_cache *cache, void *object, u8 tag); +struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, + void *object, u8 tag); #if defined(CONFIG_KASAN_GENERIC) && \ (defined(CONFIG_SLAB) || defined(CONFIG_SLUB)) diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 6f8f2bf8f53b..96d2657fe70f 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -159,26 +159,6 @@ static void describe_object_addr(struct kmem_cache *cache, void *object, (void *)(object_addr + cache->object_size)); } -static struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, - void *object, u8 tag) -{ - struct kasan_alloc_meta *alloc_meta; - int i = 0; - - alloc_meta = get_alloc_info(cache, object); - -#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY - for (i = 0; i < KASAN_NR_FREE
[PATCH v4 1/4] rcu/kasan: record and print call_rcu() call stack
This feature will record the last two call_rcu() call stacks and prints up to 2 call_rcu() call stacks in KASAN report. When call_rcu() is called, we store the call_rcu() call stack into slub alloc meta-data, so that the KASAN report can print rcu stack. [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437 [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ Signed-off-by: Walter Wu Suggested-by: Dmitry Vyukov Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrew Morton Cc: Paul E. McKenney Cc: Josh Triplett Cc: Mathieu Desnoyers Cc: Lai Jiangshan Cc: Joel Fernandes --- include/linux/kasan.h | 2 ++ kernel/rcu/tree.c | 2 ++ lib/Kconfig.kasan | 2 ++ mm/kasan/common.c | 4 ++-- mm/kasan/generic.c| 19 +++ mm/kasan/kasan.h | 10 ++ mm/kasan/report.c | 24 7 files changed, 61 insertions(+), 2 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 31314ca7c635..23b7ee00572d 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } void kasan_cache_shrink(struct kmem_cache *cache); void kasan_cache_shutdown(struct kmem_cache *cache); +void kasan_record_aux_stack(void *ptr); #else /* CONFIG_KASAN_GENERIC */ static inline void kasan_cache_shrink(struct kmem_cache *cache) {} static inline void kasan_cache_shutdown(struct kmem_cache *cache) {} +static inline void kasan_record_aux_stack(void *ptr) {} #endif /* CONFIG_KASAN_GENERIC */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 06548e2ebb72..36a4ff7f320b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "../time/tick-internal.h" #include "tree.h" @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) head->func = func; head->next = NULL; local_irq_save(flags); + kasan_record_aux_stack(head); rdp = this_cpu_ptr(_data); /* Add the callback to our list. */ diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index 81f5464ea9e1..4e83cf6e3caa 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -58,6 +58,8 @@ config KASAN_GENERIC For better error detection enable CONFIG_STACKTRACE. Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB (the resulting kernel does not boot). + In generic mode KASAN prints the last two call_rcu() call stacks in + reports. config KASAN_SW_TAGS bool "Software tag-based mode" diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 2906358e42f0..8bc618289bb1 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -41,7 +41,7 @@ #include "kasan.h" #include "../slab.h" -static inline depot_stack_handle_t save_stack(gfp_t flags) +depot_stack_handle_t kasan_save_stack(gfp_t flags) { unsigned long entries[KASAN_STACK_DEPTH]; unsigned int nr_entries; @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags) static inline void set_track(struct kasan_track *track, gfp_t flags) { track->pid = current->pid; - track->stack = save_stack(flags); + track->stack = kasan_save_stack(flags); } void kasan_enable_current(void) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 56ff8885fe2e..3372bdcaf92a 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -325,3 +325,22 @@ DEFINE_ASAN_SET_SHADOW(f2); DEFINE_ASAN_SET_SHADOW(f3); DEFINE_ASAN_SET_SHADOW(f5); DEFINE_ASAN_SET_SHADOW(f8); + +void kasan_record_aux_stack(void *addr) +{ + struct page *page = kasan_addr_to_page(addr); + struct kmem_cache *cache; + struct kasan_alloc_meta *alloc_info; + void *object; + + if (!(page && PageSlab(page))) + return; + + cache = page->slab_cache; + object = nearest_obj(cache, page, addr); + alloc_info = get_alloc_info(cache, object); + + /* record the last two call_rcu() call stacks */ + alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); +} diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index e8f37199d885..a7391bc83070 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -104,7 +104,15 @@ struct kasan_track { struct kasan_alloc_meta { struct kasan_track alloc_track; +#ifdef CONFIG_KASAN_GENERIC + /* +* call_rcu() call stack is stored into struct kasan_alloc_meta. +* The free stack is stored into struct kasan_free_meta. +*/ + depot_stack_handle_t aux_stack[2]; +#else struct kasan_track free_track[KASAN_NR_FREE_STACKS]; +#endif #ifdef CON