Thread (12 messages) 12 messages, 4 authors, 2017-11-30

kasan: false use-after-scope warnings with KCOV

From: mark.rutland@arm.com (Mark Rutland)
Date: 2017-11-28 15:24:12
Also in: lkml
Subsystem: arm64 port (aarch64 architecture), kasan, memory management, the rest · Maintainers: Catalin Marinas, Will Deacon, Andrey Ryabinin, Andrew Morton, Linus Torvalds

On Tue, Nov 28, 2017 at 02:13:55PM +0000, Mark Rutland wrote:
On Tue, Nov 28, 2017 at 01:57:49PM +0100, Dmitry Vyukov wrote:
quoted
On Tue, Nov 28, 2017 at 1:35 PM, Mark Rutland [off-list ref] wrote:
quoted
As a heads-up, I'm seeing a number of what appear to be false-positive
use-after-scope warnings when I enable both KCOV and KASAN (inline or outline),
when using the Linaro 17.08 GCC7.1.1 for arm64. So far I haven't spotted these
without KCOV selected, and I'm only seeing these for sanitize-use-after-scope.

The reports vary depending on configuration even with the same trigger. I'm not
sure if it's the reporting that's misleading, or whether the detection is going
wrong.
... it looks suspiciously like something is setting up non-zero shadow
bytes, but not zeroing them upon return.
It looks like this is the case.

The hack below detects leftover poison on an exception return *before*
the false-positive warning (example splat at the end of the email). With
scripts/Makefile.kasan hacked to not pass
-fsanitize-address-use-after-scope, I see no leftover poison.

Unfortunately, there's not enough information left to say where exactly
that happened.

Given the report that Andrey linked to [1], it looks like the compiler
is doing something wrong, and failing to clear some poison in some
cases. Dennis noted [2] that this appears to be the case where inline
functions are called in a loop.

It sounds like this is a general GCC 7.x problem, on both x86_64 and
arm64. As we don't have a smoking gun, it's still possible that
something else is corrupting the shadow, but it seems unlikely.

[1] https://lkml.kernel.org/r/20171128124534.3jvuala525wvn64r at wfg-t540p.sh.intel.com
[2] https://lkml.kernel.org/r/20171127210301.GA55812 at localhost.corp.microsoft.com

Thanks,
Mark.

Hack
--------
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 6d14b8f29b5f..8191e122d6f4 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -220,6 +220,8 @@ alternative_else_nop_endif
        .endm
 
        .macro  kernel_exit, el
+       mov     x0, sp
+       bl      kasan_assert_task_stack_is_clean_below
        .if     \el != 0
        disable_daif
 
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 405bba487df5..dab8a51ee52f 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -37,6 +37,8 @@
 #include <linux/vmalloc.h>
 #include <linux/bug.h>
 
+#include <asm/stacktrace.h>
+
 #include "kasan.h"
 #include "../slab.h"
 
@@ -241,6 +243,33 @@ static __always_inline bool memory_is_poisoned(unsigned long addr, size_t size)
        return memory_is_poisoned_n(addr, size);
 }
 
+/*
+ * In some contexts (e.g. when returning from an exception), all shadow beyond
+ * a certain point on the stack should be clear. This helper can be called by
+ * assembly code to verify this is the case.
+ */
+asmlinkage void kasan_assert_task_stack_is_clean_below(unsigned long watermark)
+{
+       unsigned long base;
+
+       /*
+        * This is an arm64-specific hack. This should be fixed properly to
+        * discover and check the bounds of the current stack in an
+        * arch-agnostic manner.
+        */
+       if (!on_task_stack(current, watermark))
+               return;
+
+       /*
+        * Calculate the task stack base address.  Avoid using 'current'
+        * because this function is called by early resume code which hasn't
+        * yet set up the percpu register (%gs).
+        */
+       base = watermark & ~(THREAD_SIZE - 1);
+
+       WARN_ON_ONCE(memory_is_poisoned(base, watermark - base));
+}
+
 static __always_inline void check_memory_region_inline(unsigned long addr,
                                                size_t size, bool write,
                                                unsigned long ret_ip)
--------
Splat
--------
[  186.951300] WARNING: CPU: 1 PID: 2429 at mm/kasan/kasan.c:270 kasan_assert_task_stack_is_clean_below+0x144/0x150
[  186.961418] Modules linked in:
[  186.964468] CPU: 1 PID: 2429 Comm: perf Not tainted 4.15.0-rc1-00001-g7780802c256e #6
[  186.972249] Hardware name: ARM Juno development board (r1) (DT)
[  186.978133] task: ffff800933fe6900 task.stack: ffff80092c990000
[  186.984019] pstate: 200003c5 (nzCv DAIF -PAN -UAO)
[  186.988789] pc : kasan_assert_task_stack_is_clean_below+0x144/0x150
[  186.995022] lr : ret_fast_syscall+0x34/0x98
[  186.999177] sp : ffff80092c997ec0
[  187.002472] x29: ffff80092c997ff0 x28: ffff800933fe6900 
[  187.007760] x27: ffff200009264000 x26: 00000000000000f1 
[  187.013047] x25: 0000000000000124 x24: 0000000000000015 
[  187.018334] x23: 0000000060000000 x22: 0000ffffae4b7554 
[  187.023621] x21: 00000000ffffffff x20: 000060092de30000 
[  187.028908] x19: 0000000000000000 x18: 0000ffffd2ec5330 
[  187.034195] x17: 0000ffffae4b7530 x16: ffff200008270508 
[  187.039482] x15: 0000ffffae538588 x14: 0000000000000000 
[  187.044769] x13: ffffffffffffffff x12: ffffffffffffffff 
[  187.050060] x11: 1ffff00125932f33 x10: ffff100125932f33 
[  187.055349] x9 : dfff200000000000 x8 : dfff200000000008 
[  187.060638] x7 : 1ffff00125932fd7 x6 : ffff100125932fd7 
[  187.065927] x5 : ffff80092c997ebf x4 : ffff100125932fd8 
[  187.071217] x3 : dfff200000000000 x2 : ffff100125932e30 
[  187.076506] x1 : ffff100125932e28 x0 : 00000000000000f8 
[  187.081793] Call trace:
[  187.084238]  kasan_assert_task_stack_is_clean_below+0x144/0x150
[  187.090122] ---[ end trace 9c3a99d1de859687 ]---
[  187.212571] ==================================================================
[  187.219786] BUG: KASAN: use-after-scope in __save_stack_trace+0x1c8/0x2f0
[  187.226537] Read of size 4 at addr ffff800930e4f048 by task true/2432
[  187.232935] 
[  187.234430] CPU: 2 PID: 2432 Comm: true Tainted: G        W        4.15.0-rc1-00001-g7780802c256e #6
[  187.243507] Hardware name: ARM Juno development board (r1) (DT)
[  187.249389] Call trace:
[  187.251830]  dump_backtrace+0x0/0x320
[  187.255477]  show_stack+0x20/0x30
[  187.258782]  dump_stack+0x108/0x174
[  187.262256]  print_address_description+0x60/0x270
[  187.266936]  kasan_report+0x210/0x2f0
[  187.270584]  __asan_load4+0x84/0xa8
[  187.274059]  __save_stack_trace+0x1c8/0x2f0
[  187.278224]  save_stack_trace+0x24/0x30
[  187.282044]  kasan_kmalloc+0xd0/0x180
[  187.285688]  kasan_slab_alloc+0x14/0x20
[  187.289508]  kmem_cache_alloc+0x128/0x1e8
[  187.293499]  perf_event_mmap+0x2dc/0x968
[  187.297405]  mmap_region+0x24c/0xa60
[  187.300963]  do_mmap+0x404/0x640
[  187.304178]  vm_mmap_pgoff+0x15c/0x190
[  187.307909]  vm_mmap+0x70/0xb0
[  187.310951]  elf_map+0x114/0x150
[  187.314165]  load_elf_binary+0x728/0x1b84
[  187.318158]  search_binary_handler+0xe4/0x3b8
[  187.322495]  do_execveat_common.isra.12+0xaa4/0xc60
[  187.327349]  SyS_execve+0x48/0x60
[  187.330650]  el0_svc_naked+0x20/0x24
[  187.334202] 
[  187.335685] The buggy address belongs to the page:
[  187.340453] page:ffff7e0024c393c0 count:0 mapcount:0 mapping:          (null) index:0x0
[  187.348414] flags: 0x1fffc00000000000()
[  187.352240] raw: 1fffc00000000000 0000000000000000 0000000000000000 00000000ffffffff
[  187.359947] raw: 0000000000000000 ffff7e0024c393e0 0000000000000000 0000000000000000
[  187.367643] page dumped because: kasan: bad access detected
[  187.373178] 
[  187.374661] Memory state around the buggy address:
[  187.379428]  ffff800930e4ef00: f1 f1 f8 f2 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f2 f2
[  187.386612]  ffff800930e4ef80: f2 f2 00 00 f2 f2 f3 f3 f3 f3 f8 f8 f8 f8 f8 f8
[  187.393795] >ffff800930e4f000: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 00 00 00 00 00 00
[  187.400973]                                               ^
[  187.406516]  ffff800930e4f080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  187.413699]  ffff800930e4f100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  187.420877] ==================================================================
--------
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help