kasan: fix pc crash if open kasan with vmap stack [1/1]
authorTao Zeng <tao.zeng@amlogic.com>
Fri, 25 Oct 2019 07:01:24 +0000 (15:01 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Mon, 4 Nov 2019 06:04:38 +0000 (23:04 -0700)
PD#SWPL-10141

Problem:
If open KASAN, connect wifi, and auto-start apk dianshijia, it will
soon crash as:
[ 56.655524@2] Unable to handle kernel NULL pointer dereference
               at virtual address 00000050
[ 56.658155@2] pgd = d0104000
[ 56.661008@2] [00000050] *pgd=00000000
[ 56.664744@2] Internal error: Oops: 80000005 1 PREEMPT SMP ARM
               common(O) firmware(O) media_clock(O) tb_detect(O)
               dnlp_alg ldim_alg mxl661_fe_32(O)
[ 56.709028@2] CPU: 2 PID: 4930 Comm: kworker/u9:3 Tainted: O 4.9.113 #1
[ 56.716908@2] Hardware name: Generic DT based system
[ 56.721858@2] task: f2632bc0 task.stack: c2010000
[ 56.726530@2] PC is at 0x50
[ 56.729301@2] LR is at 0x0

Solution:
Fix wrong pmd check address

Verify:
TL1 X301

Change-Id: I85e01418789801e0ef7691a9d8963c233e115b28
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
arch/arm/kernel/entry-armv.S
drivers/amlogic/memory_ext/vmap_stack.c

index 51c5758..4bd8391 100644 (file)
 /*
  * Interrupt handling.
  */
-       .macro  irq_handler
 #ifdef CONFIG_AMLOGIC_VMAP
+       .macro  irq_handler, vmap=0
+       .if \vmap
        mov     r8, sp                  /* back up sp */
        mov     r0, sp
        bl      irq_stack_entry         /* switch IRQ stack */
        mov     sp, r0
+       .endif
+#else
+       .macro  irq_handler
 #endif
 #ifdef CONFIG_MULTI_IRQ_HANDLER
        ldr     r1, =handle_arch_irq
@@ -59,7 +63,9 @@
 #endif
 9997:
 #ifdef CONFIG_AMLOGIC_VMAP
+       .if \vmap
        mov     sp, r8                  /* switch stack back to task stack */
+       .endif
 #endif
        .endm
 
@@ -226,8 +232,14 @@ ENDPROC(__und_invalid)
         * get fault task thread info
         */
        ldr     r0, [sp, #(SVC_REGS_SIZE + TI_VMAP_BACK_SP)]
+#ifdef CONFIG_AMLOGIC_KASAN32
+       /* FAR may be kasan shadow then nobody will handle it */
        mrc     p15, 0, r1, c6, c0, 0           @ get FAR
        bl      pmd_check
+#endif
+       /* sp may not access able when swith task */
+       mov     r1, r0
+       bl      pmd_check
        mov     tsk, r0
        mov     tsk, tsk, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT
        mov     tsk, tsk, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
@@ -294,7 +306,11 @@ __dabt_svc:
        sub     r0, #SVC_REGS_SIZE
        mov     r1, sp
        mov     r2, #SVC_REGS_SIZE
+#ifdef CONFIG_AMLOGIC_KASAN32
+       bl      __memcpy                /* copy back sp */
+#else
        bl      memcpy                  /* copy back sp */
+#endif
        mov     sp, r0
 #else
        svc_entry uaccess=0
@@ -309,7 +325,11 @@ ENDPROC(__dabt_svc)
        .align  5
 __irq_svc:
        svc_entry
+#ifdef CONFIG_AMLOGIC_VMAP
+       irq_handler vmap=1
+#else
        irq_handler
+#endif
 
 #ifdef CONFIG_PREEMPT
        ldr     r8, [tsk, #TI_PREEMPT]          @ get preempt count
index 2d25772..cbceeeb 100644 (file)
@@ -181,12 +181,12 @@ unsigned long notrace pmd_check(unsigned long addr, unsigned long far)
        pud_t *pud, *pud_k;
        pmd_t *pmd, *pmd_k;
 
-       if (addr < TASK_SIZE)
+       if (far < TASK_SIZE)
                return addr;
 
-       index = pgd_index(addr);
+       index = pgd_index(far);
 
-       pgd = cpu_get_pgd() + index;
+       pgd   = cpu_get_pgd() + index;
        pgd_k = init_mm.pgd + index;
 
        if (pgd_none(*pgd_k))
@@ -194,16 +194,16 @@ unsigned long notrace pmd_check(unsigned long addr, unsigned long far)
        if (!pgd_present(*pgd))
                set_pgd(pgd, *pgd_k);
 
-       pud = pud_offset(pgd, addr);
-       pud_k = pud_offset(pgd_k, addr);
+       pud   = pud_offset(pgd, far);
+       pud_k = pud_offset(pgd_k, far);
 
        if (pud_none(*pud_k))
                goto bad_area;
        if (!pud_present(*pud))
                set_pud(pud, *pud_k);
 
-       pmd = pmd_offset(pud, addr);
-       pmd_k = pmd_offset(pud_k, addr);
+       pmd   = pmd_offset(pud, far);
+       pmd_k = pmd_offset(pud_k, far);
 
 #ifdef CONFIG_ARM_LPAE
        /*
@@ -219,7 +219,7 @@ unsigned long notrace pmd_check(unsigned long addr, unsigned long far)
         * pmd_none() check for the entry really corresponded to address, not
         * for the first of pair.
         */
-       index = (addr >> SECTION_SHIFT) & 1;
+       index = (far >> SECTION_SHIFT) & 1;
 #endif
        if (pmd_none(pmd_k[index]))
                goto bad_area;