[PATCH] ARM: stacktrace: disregard .entry.text when looking for exception frames
Ard Biesheuvel
ardb at kernel.org
Thu Oct 29 14:59:28 EDT 2020
On Thu, 29 Oct 2020 at 01:18, Ard Biesheuvel <ardb at kernel.org> wrote:
>
> Commit c608906165355089 ("ARM: probes: avoid adding kprobes to sensitive
> kernel-entry/exit code") reorganized the section layout to prevent entry
> code from being instrumented by kprobes.
>
> This resulted in stack frames referring to back to entry code to be
> misidentified as exception frames, resulting in splats like the below
> when KASAN is enabled:
>
> ==================================================================
> BUG: KASAN: stack-out-of-bounds in save_trace+0xc1/0xf8
> Read of size 4 at addr df01f89c by task bash/3421
>
> CPU: 12 PID: 3421 Comm: bash Not tainted 5.10.0-rc1-kasan+ #219
> Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015
> [<c0411765>] (unwind_backtrace) from [<c040ba8b>] (show_stack+0xb/0xc)
> [<c040ba8b>] (show_stack) from [<c121c5e5>] (dump_stack+0x8d/0xa0)
> [<c121c5e5>] (dump_stack) from [<c05bd87b>] (print_address_description.constprop.3+0x2b/0x368)
> [<c05bd87b>] (print_address_description.constprop.3) from [<c05bdd2d>] (kasan_report+0xfd/0x114)
> [<c05bdd2d>] (kasan_report) from [<c040b629>] (save_trace+0xc1/0xf8)
> [<c040b629>] (save_trace) from [<c040b563>] (walk_stackframe+0x1b/0x20)
> [<c040b563>] (walk_stackframe) from [<c040b759>] (__save_stack_trace+0xf9/0x100)
> [<c040b759>] (__save_stack_trace) from [<c04cb169>] (stack_trace_save+0x71/0x88)
> [<c04cb169>] (stack_trace_save) from [<c05bcd9d>] (kasan_save_stack+0x11/0x28)
> [<c05bcd9d>] (kasan_save_stack) from [<c05bcdd1>] (kasan_set_track+0x1d/0x20)
> [<c05bcdd1>] (kasan_set_track) from [<c05be421>] (kasan_set_free_info+0x19/0x20)
> [<c05be421>] (kasan_set_free_info) from [<c05bcd67>] (__kasan_slab_free+0xa7/0xcc)
> [<c05bcd67>] (__kasan_slab_free) from [<c05bbe41>] (kmem_cache_free+0x59/0x21c)
> [<c05bbe41>] (kmem_cache_free) from [<c04c1fdb>] (rcu_core+0x2d7/0x988)
> [<c04c1fdb>] (rcu_core) from [<c04014ab>] (__do_softirq+0x133/0x41c)
> [<c04014ab>] (__do_softirq) from [<c044d4c9>] (irq_exit+0xb5/0xcc)
> [<c044d4c9>] (irq_exit) from [<c04a8503>] (__handle_domain_irq+0x5f/0xa8)
> [<c04a8503>] (__handle_domain_irq) from [<c08d5cb5>] (gic_handle_irq+0x3d/0x8c)
> [<c08d5cb5>] (gic_handle_irq) from [<c0400c11>] (__irq_svc+0x51/0x7c)
> Exception stack(0xdf01f7f8 to 0xdf01f840)
> f7e0: df01f8e0 df01f8a0
> f800: 00000008 df01fc7c 000000ad df01f960 df01f8e0 00000008 bae03f10 df01fc58
> f820: df01f8a0 0000000a c040b660 df01f848 c04114eb c04110b8 20000033 ffffffff
> [<c0400c11>] (__irq_svc) from [<c04110b8>] (unwind_pop_register+0x0/0x58)
> [<c04110b8>] (unwind_pop_register) from [<c0400161>] (ret_fast_syscall+0x1/0x5a)
> Exception stack(0xdf01f860 to 0xdf01f8a8)
> f860: 41b58ab3 c1f939e0 c04111ec 00000000 d129e800 c0411311 df01fa44 df01fa4c
> f880: 41b58ab3 c1f939e0 c04111ec 00000001 00000003 c040b569 df01f8c0 df01c000
> f8a0: df01fc7c df01ffa8
> ...
>
> addr df01f89c is located in stack of task bash/3421 at offset 28 in frame:
> unwind_frame+0x0/0x578
>
> Here, the last entry represents a call to unwind_pop_register frame() with
> the return address set to ret_fast_syscall, and since in_entry_text() returns
> true for that return address, save_trace() treats it as an exception frame,
> and attempts to dereference the struct pt_regs pointer to access the ARM_pc
> value. With KASAN instrumentation enabled, this results in a read from an
> address which is annotated as out of bounds, resulting in the splat.
>
> (Note that the KASAN response is triggered inside the KASAN machinery
> itself, which records stack traces for memory allocation and free actions.
> While recording such a stack trace, the out of bounds access triggered
> the response above, resulting in yet another walk of the call stack, but
> this time KASAN was no longer mediating the memory accesses. The same
> stack frame is misidentified a second time, which is why the trace above
> contains 'Exception stack(0xdf01f860 to 0xdf01f8a8)' which is not really
> an exception stack at all.)
>
> So the correct thing to do here is to disregard .entry.text, and only take
> true exception frames into account. So we need to use __in_irqentry_text()
> instead, in two places: in save_trace(), which KASAN uses to record the
> stack traces, and in dump_backtrace_entry(), which prints the exception
> stack to the kernel log like above.
>
> Fixes: c608906165355089 ("ARM: probes: avoid adding kprobes to sensitive ...")
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
> arch/arm/kernel/stacktrace.c | 2 +-
> arch/arm/kernel/traps.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
> index 76ea4178a55c..56a7abdc1b96 100644
> --- a/arch/arm/kernel/stacktrace.c
> +++ b/arch/arm/kernel/stacktrace.c
> @@ -112,7 +112,7 @@ static int save_trace(struct stackframe *frame, void *d)
> if (trace->nr_entries >= trace->max_entries)
> return 1;
>
> - if (!in_entry_text(frame->pc))
> + if (!__in_irqentry_text(frame->pc))
> return 0;
>
> regs = (struct pt_regs *)frame->sp;
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index 17d5a785df28..30628daa80b4 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -75,7 +75,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from,
> loglvl, where, from);
> #endif
>
> - if (in_entry_text(from) && end <= ALIGN(frame, THREAD_SIZE))
> + if (__in_irqentry_text(from) && end <= ALIGN(frame, THREAD_SIZE))
> dump_mem(loglvl, "Exception stack", frame + 4, end);
> }
>
This is not quite correct - identifying the exception frame should be
based on 'where' not 'from' when relying on .irqentry.text annotations
but we don't emit those unless CONFIG_FUNCTION_GRAPH_TRACER is
enabled.
I don't understand this well enough to disentangle it, and other
KASAN-enabled architectures simply disable instrumentation for the
stack traversal code, so I propose we do the same for ARM
I.e.,
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 6a44ffd9c7b4..dad77b0bb734 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -21,6 +21,9 @@ obj-y := elf.o entry-common.o irq.o opcodes.o \
setup.o signal.o sigreturn_codes.o \
stacktrace.o sys_arm.o time.o traps.o
+KASAN_SANITIZE_stacktrace.o := n
+KASAN_SANITIZE_traps.o := n
+
ifneq ($(CONFIG_ARM_UNWIND),y)
obj-$(CONFIG_FRAME_POINTER) += return_address.o
endif
More information about the linux-arm-kernel
mailing list