kasan: fix wrong kasan report when resume [1/1]
authorTao Zeng <tao.zeng@amlogic.com>
Wed, 24 Apr 2019 08:10:03 +0000 (16:10 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Sun, 28 Apr 2019 02:08:31 +0000 (19:08 -0700)
PD#SWPL-7676

Problem:
If we open kasan on 32bit kernel, after resume we usually will
get a stack-out-of-bounds KASAN error report. But infact that's
a fake report. Because On arm architecture, cpu suspend/resume
routine is done in function call path:
    cpu_suspend -> psci_cpu_suspend -> __invoke_psci_fn_smc
during this call path, some parts of stack will be marked as
shadow memory. But when cpu resume from smc call, it directly
return to point which saved in cpu_suspend and call resume
procedure. Which do not comeback as a reverse return path:
    __invoke_psci_fn_smc -> psci_cpu_suspend -> cpu_suspend
So some residual shadow memory may affect KASAN report when
cpu is calling resume hooks.

Solution:
We just need to clear all shadow in stack for this case.

Verify:
p212

Change-Id: Ic6c877212240d03902b11184e54ac363455e0094
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
arch/arm/kernel/sleep.S
arch/arm/mm/kasan_init.c

index dd52f5c..28e7b0d 100644 (file)
@@ -112,6 +112,10 @@ ENDPROC(cpu_resume_mmu)
        .popsection
 cpu_resume_after_mmu:
        bl      cpu_init                @ restore the und/abt/irq banked regs
+#ifdef CONFIG_AMLOGIC_KASAN32
+       mov     r0, sp
+       bl      kasan_clear_shadow_for_resume
+#endif
        mov     r0, #0                  @ return zero on success
        ldmfd   sp!, {r4 - r11, pc}
 ENDPROC(cpu_resume_after_mmu)
index ac26904..cd16c6f 100644 (file)
@@ -154,7 +154,8 @@ static void kasan_alloc_and_map_shadow(unsigned long start, unsigned long end)
 
 void __init kasan_init(void)
 {
-       unsigned long start, end;
+       unsigned long start, end, mem_size = 0;
+       struct memblock_region *reg;
        int i;
 
        /*
@@ -169,7 +170,17 @@ void __init kasan_init(void)
        cpu_switch_mm(tmp_pg_dir, &init_mm);
        clear_pmds(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
-       kasan_alloc_and_map_shadow(PAGE_OFFSET, KMEM_END);
+       for_each_memblock(memory, reg) {
+               mem_size += reg->size;
+       }
+       /* create shadow for linear map space */
+       if (mem_size < (KMEM_END - PAGE_OFFSET))
+               end = PAGE_OFFSET + mem_size;
+       else
+               end = KMEM_END;
+       pr_info("%s, total mem size:%lx, end:%lx\n", __func__, mem_size, end);
+
+       kasan_alloc_and_map_shadow(PAGE_OFFSET, end);
        kasan_alloc_and_map_shadow(FIXADDR_START, FIXADDR_END);
 #ifdef CONFIG_HIGHMEM
        kasan_alloc_and_map_shadow(PKMAP_BASE,
@@ -216,3 +227,28 @@ void __init kasan_init(void)
        init_task.kasan_depth = 0;
        pr_info("KernelAddressSanitizer initialized\n");
 }
+
+/*
+ * This is work around for mis-report of KASAN when resume.
+ * On arm architecture, cpu suspend/resume routine is done in
+ * function call path:
+ *    cpu_suspend -> psci_cpu_suspend -> __invoke_psci_fn_smc
+ * during this call path, some parts of stack will be marked as
+ * shadow memory. But when cpu resume from smc call, it directly
+ * return to point which saved in cpu_suspend and call resume
+ * procedure. Which do not comeback as a reverse return path:
+ *    __invoke_psci_fn_smc -> psci_cpu_suspend -> cpu_suspend
+ * So some residual shadow memory may affect KASAN report when
+ * cpu is calling resume hooks.
+ * We just need to clear all shadow in stack for this case.
+ */
+void kasan_clear_shadow_for_resume(unsigned long sp)
+{
+       unsigned long size;
+
+       size = sp &  (THREAD_SIZE - 1);
+       sp   = sp & ~(THREAD_SIZE - 1);
+       size = ALIGN(size, (1 << KASAN_SHADOW_SCALE_SHIFT));
+       pr_debug("%s, sp:%lx, size:%lx\n", __func__, sp, size);
+       kasan_unpoison_shadow((void *)sp, size);
+}