| From 57bb4b95298e5c09882abd9929e4e9ce3e154022 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 15 Sep 2022 17:04:13 +0200 |
| Subject: x86: kmsan: don't instrument stack walking functions |
| |
| From: Alexander Potapenko <glider@google.com> |
| |
| [ Upstream commit 37ad4ee8364255c73026a3c343403b5977fa7e79 ] |
| |
| Upon function exit, KMSAN marks local variables as uninitialized. Further |
| function calls may result in the compiler creating the stack frame where |
| these local variables resided. This results in frame pointers being |
| marked as uninitialized data, which is normally correct, because they are |
| not stack-allocated. |
| |
| However stack unwinding functions are supposed to read and dereference the |
| frame pointers, in which case KMSAN might be reporting uses of |
| uninitialized values. |
| |
| To work around that, we mark update_stack_state(), unwind_next_frame() and |
| show_trace_log_lvl() with __no_kmsan_checks, preventing all KMSAN reports |
| inside those functions and making them return initialized values. |
| |
| Link: https://lkml.kernel.org/r/20220915150417.722975-40-glider@google.com |
| Signed-off-by: Alexander Potapenko <glider@google.com> |
| Cc: Alexander Viro <viro@zeniv.linux.org.uk> |
| Cc: Alexei Starovoitov <ast@kernel.org> |
| Cc: Andrey Konovalov <andreyknvl@gmail.com> |
| Cc: Andrey Konovalov <andreyknvl@google.com> |
| Cc: Andy Lutomirski <luto@kernel.org> |
| Cc: Arnd Bergmann <arnd@arndb.de> |
| Cc: Borislav Petkov <bp@alien8.de> |
| Cc: Christoph Hellwig <hch@lst.de> |
| Cc: Christoph Lameter <cl@linux.com> |
| Cc: David Rientjes <rientjes@google.com> |
| Cc: Dmitry Vyukov <dvyukov@google.com> |
| Cc: Eric Biggers <ebiggers@google.com> |
| Cc: Eric Biggers <ebiggers@kernel.org> |
| Cc: Eric Dumazet <edumazet@google.com> |
| Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: Herbert Xu <herbert@gondor.apana.org.au> |
| Cc: Ilya Leoshkevich <iii@linux.ibm.com> |
| Cc: Ingo Molnar <mingo@redhat.com> |
| Cc: Jens Axboe <axboe@kernel.dk> |
| Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> |
| Cc: Kees Cook <keescook@chromium.org> |
| Cc: Marco Elver <elver@google.com> |
| Cc: Mark Rutland <mark.rutland@arm.com> |
| Cc: Matthew Wilcox <willy@infradead.org> |
| Cc: Michael S. Tsirkin <mst@redhat.com> |
| Cc: Pekka Enberg <penberg@kernel.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Petr Mladek <pmladek@suse.com> |
| Cc: Stephen Rothwell <sfr@canb.auug.org.au> |
| Cc: Steven Rostedt <rostedt@goodmis.org> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Vasily Gorbik <gor@linux.ibm.com> |
| Cc: Vegard Nossum <vegard.nossum@oracle.com> |
| Cc: Vlastimil Babka <vbabka@suse.cz> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Stable-dep-of: ced37e9ceae5 ("x86/dumpstack: Prevent KASAN false positive warnings in __show_regs()") |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/x86/kernel/dumpstack.c | 6 ++++++ |
| arch/x86/kernel/unwind_frame.c | 11 +++++++++++ |
| 2 files changed, 17 insertions(+) |
| |
| diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c |
| index 7a1fe0d382ce6..df6d3d859ca1b 100644 |
| --- a/arch/x86/kernel/dumpstack.c |
| +++ b/arch/x86/kernel/dumpstack.c |
| @@ -183,6 +183,12 @@ static void show_regs_if_on_stack(struct stack_info *info, struct pt_regs *regs, |
| } |
| } |
| |
| +/* |
| + * This function reads pointers from the stack and dereferences them. The |
| + * pointers may not have their KMSAN shadow set up properly, which may result |
| + * in false positive reports. Disable instrumentation to avoid those. |
| + */ |
| +__no_kmsan_checks |
| static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| unsigned long *stack, const char *log_lvl) |
| { |
| diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c |
| index d7c44b257f7f4..8943114f9ebed 100644 |
| --- a/arch/x86/kernel/unwind_frame.c |
| +++ b/arch/x86/kernel/unwind_frame.c |
| @@ -183,6 +183,16 @@ static struct pt_regs *decode_frame_pointer(unsigned long *bp) |
| } |
| #endif |
| |
| +/* |
| + * While walking the stack, KMSAN may stomp on stale locals from other |
| + * functions that were marked as uninitialized upon function exit, and |
| + * now hold the call frame information for the current function (e.g. the frame |
| + * pointer). Because KMSAN does not specifically mark call frames as |
| + * initialized, false positive reports are possible. To prevent such reports, |
| + * we mark the functions scanning the stack (here and below) with |
| + * __no_kmsan_checks. |
| + */ |
| +__no_kmsan_checks |
| static bool update_stack_state(struct unwind_state *state, |
| unsigned long *next_bp) |
| { |
| @@ -251,6 +261,7 @@ static bool update_stack_state(struct unwind_state *state, |
| return true; |
| } |
| |
| +__no_kmsan_checks |
| bool unwind_next_frame(struct unwind_state *state) |
| { |
| struct pt_regs *regs; |
| -- |
| 2.51.0 |
| |