mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
kasan: fix pc crash if open kasan with vmap stack [1/1]
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>
This commit is contained in:
@@ -38,12 +38,16 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
@@ -179,12 +179,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))
|
||||
@@ -192,16 +192,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
|
||||
/*
|
||||
@@ -217,7 +217,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;
|
||||
|
||||
Reference in New Issue
Block a user