Skip to content

Commit 2f004ee

Browse files
thejhsuryasaimadhu
authored andcommitted
x86/kasan: Print original address on #GP
Make #GP exceptions caused by out-of-bounds KASAN shadow accesses easier to understand by computing the address of the original access and printing that. More details are in the comments in the patch. This turns an error like this: kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault, probably for non-canonical address 0xe017577ddf75b7dd: 0000 [#1] PREEMPT SMP KASAN PTI into this: general protection fault, probably for non-canonical address 0xe017577ddf75b7dd: 0000 [#1] PREEMPT SMP KASAN PTI KASAN: maybe wild-memory-access in range [0x00badbeefbadbee8-0x00badbeefbadbeef] The hook is placed in architecture-independent code, but is currently only wired up to the X86 exception handler because I'm not sufficiently familiar with the address space layout and exception handling mechanisms on other architectures. Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: kasan-dev@googlegroups.com Cc: linux-mm <linux-mm@kvack.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sean Christopherson <sean.j.christopherson@intel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: x86-ml <x86@kernel.org> Link: https://lkml.kernel.org/r/20191218231150.12139-4-jannh@google.com
1 parent aa49f20 commit 2f004ee

File tree

4 files changed

+48
-21
lines changed

4 files changed

+48
-21
lines changed

arch/x86/kernel/dumpstack.c

+2
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ void die_addr(const char *str, struct pt_regs *regs, long err, long gp_addr)
427427
int sig = SIGSEGV;
428428

429429
__die_header(str, regs, err);
430+
if (gp_addr)
431+
kasan_non_canonical_hook(gp_addr);
430432
if (__die_body(str, regs, err))
431433
sig = 0;
432434
oops_end(flags, regs, sig);

arch/x86/mm/kasan_init_64.c

-21
Original file line numberDiff line numberDiff line change
@@ -288,23 +288,6 @@ static void __init kasan_shallow_populate_pgds(void *start, void *end)
288288
} while (pgd++, addr = next, addr != (unsigned long)end);
289289
}
290290

291-
#ifdef CONFIG_KASAN_INLINE
292-
static int kasan_die_handler(struct notifier_block *self,
293-
unsigned long val,
294-
void *data)
295-
{
296-
if (val == DIE_GPF) {
297-
pr_emerg("CONFIG_KASAN_INLINE enabled\n");
298-
pr_emerg("GPF could be caused by NULL-ptr deref or user memory access\n");
299-
}
300-
return NOTIFY_OK;
301-
}
302-
303-
static struct notifier_block kasan_die_notifier = {
304-
.notifier_call = kasan_die_handler,
305-
};
306-
#endif
307-
308291
void __init kasan_early_init(void)
309292
{
310293
int i;
@@ -341,10 +324,6 @@ void __init kasan_init(void)
341324
int i;
342325
void *shadow_cpu_entry_begin, *shadow_cpu_entry_end;
343326

344-
#ifdef CONFIG_KASAN_INLINE
345-
register_die_notifier(&kasan_die_notifier);
346-
#endif
347-
348327
memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));
349328

350329
/*

include/linux/kasan.h

+6
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,10 @@ static inline void kasan_release_vmalloc(unsigned long start,
228228
unsigned long free_region_end) {}
229229
#endif
230230

231+
#ifdef CONFIG_KASAN_INLINE
232+
void kasan_non_canonical_hook(unsigned long addr);
233+
#else /* CONFIG_KASAN_INLINE */
234+
static inline void kasan_non_canonical_hook(unsigned long addr) { }
235+
#endif /* CONFIG_KASAN_INLINE */
236+
231237
#endif /* LINUX_KASAN_H */

mm/kasan/report.c

+40
Original file line numberDiff line numberDiff line change
@@ -512,3 +512,43 @@ void __kasan_report(unsigned long addr, size_t size, bool is_write, unsigned lon
512512

513513
end_report(&flags);
514514
}
515+
516+
#ifdef CONFIG_KASAN_INLINE
517+
/*
518+
* With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high
519+
* canonical half of the address space) cause out-of-bounds shadow memory reads
520+
* before the actual access. For addresses in the low canonical half of the
521+
* address space, as well as most non-canonical addresses, that out-of-bounds
522+
* shadow memory access lands in the non-canonical part of the address space.
523+
* Help the user figure out what the original bogus pointer was.
524+
*/
525+
void kasan_non_canonical_hook(unsigned long addr)
526+
{
527+
unsigned long orig_addr;
528+
const char *bug_type;
529+
530+
if (addr < KASAN_SHADOW_OFFSET)
531+
return;
532+
533+
orig_addr = (addr - KASAN_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT;
534+
/*
535+
* For faults near the shadow address for NULL, we can be fairly certain
536+
* that this is a KASAN shadow memory access.
537+
* For faults that correspond to shadow for low canonical addresses, we
538+
* can still be pretty sure - that shadow region is a fairly narrow
539+
* chunk of the non-canonical address space.
540+
* But faults that look like shadow for non-canonical addresses are a
541+
* really large chunk of the address space. In that case, we still
542+
* print the decoded address, but make it clear that this is not
543+
* necessarily what's actually going on.
544+
*/
545+
if (orig_addr < PAGE_SIZE)
546+
bug_type = "null-ptr-deref";
547+
else if (orig_addr < TASK_SIZE)
548+
bug_type = "probably user-memory-access";
549+
else
550+
bug_type = "maybe wild-memory-access";
551+
pr_alert("KASAN: %s in range [0x%016lx-0x%016lx]\n", bug_type,
552+
orig_addr, orig_addr + KASAN_SHADOW_MASK);
553+
}
554+
#endif

0 commit comments

Comments
 (0)