History

arm64: Handle el1 synchronous instruction aborts cleanly

Executing from a non-executable area gives an ugly message: lkdtm: Performing direct entry EXEC_RODATA lkdtm: attempting ok execution at ffff0000084c0e08 lkdtm: attempting bad execution at ffff000008880700 Bad mode in Synchronous Abort handler detected on CPU2, code 0x8400000e -- IABT (current EL) CPU: 2 PID: 998 Comm: sh Not tainted 4.7.0-rc2+ #13 Hardware name: linux,dummy-virt (DT) task: ffff800077e35780 ti: ffff800077970000 task.ti: ffff800077970000 PC is at lkdtm_rodata_do_nothing+0x0/0x8 LR is at execute_location+0x74/0x88 The 'IABT (current EL)' indicates the error but it's a bit cryptic without knowledge of the ARM ARM. There is also no indication of the specific address which triggered the fault. The increase in kernel page permissions makes hitting this case more likely as well. Handling the case in the vectors gives a much more familiar looking error message: lkdtm: Performing direct entry EXEC_RODATA lkdtm: attempting ok execution at ffff0000084c0840 lkdtm: attempting bad execution at ffff000008880680 Unable to handle kernel paging request at virtual address ffff000008880680 pgd = ffff8000089b2000 [ffff000008880680] *pgd=00000000489b4003, *pud=0000000048904003, *pmd=0000000000000000 Internal error: Oops: 8400000e [#1] PREEMPT SMP Modules linked in: CPU: 1 PID: 997 Comm: sh Not tainted 4.7.0-rc1+ #24 Hardware name: linux,dummy-virt (DT) task: ffff800077f9f080 ti: ffff800008a1c000 task.ti: ffff800008a1c000 PC is at lkdtm_rodata_do_nothing+0x0/0x8 LR is at execute_location+0x74/0x88

Laura Abbott committed 10 years ago

Commit 9adeb8e1 parent ad057112 files · +19 −2Browse files

Unified · Split

2 files
  1. arch/arm64/kernel/entry.S +7 −0
  2. arch/arm64/mm/fault.c +12 −2
arch/arm64/kernel/entry.S+7−0
@@ -353,6 +353,8 @@ el1_sync: · 352 unmodified lines
353 lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class353 lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class
354 cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1354 cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1
355 b.eq el1_da355 b.eq el1_da
356 cmp x24, #ESR_ELx_EC_IABT_CUR // instruction abort in EL1
357 b.eq el1_ia
356 cmp x24, #ESR_ELx_EC_SYS64 // configurable trap358 cmp x24, #ESR_ELx_EC_SYS64 // configurable trap
357 b.eq el1_undef359 b.eq el1_undef
358 cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception360 cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception
@@ -364,6 +366,11 @@ el1_sync: · 5 unmodified lines
364 cmp x24, #ESR_ELx_EC_BREAKPT_CUR // debug exception in EL1366 cmp x24, #ESR_ELx_EC_BREAKPT_CUR // debug exception in EL1
365 b.ge el1_dbg367 b.ge el1_dbg
366 b el1_inv368 b el1_inv
369
370el1_ia:
371 /*
372 * Fall through to the Data abort case
373 */
367el1_da:374el1_da:
368 /*375 /*
369 * Data abort handling376 * Data abort handling
arch/arm64/mm/fault.c+12−2
@@ -153,6 +153,11 @@ int ptep_set_access_flags(struct vm_area_struct *vma, · 152 unmodified lines
153}153}
154#endif154#endif
155 155
156static bool is_el1_instruction_abort(unsigned int esr)
157{
158 return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_CUR;
159}
160
156/*161/*
157 * The kernel tried to access some page that wasn't present.162 * The kernel tried to access some page that wasn't present.
158 */163 */
@@ -161,8 +166,9 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, · 2 unmodified lines
161{166{
162 /*167 /*
163 * Are we prepared to handle this kernel fault?168 * Are we prepared to handle this kernel fault?
169 * We are almost certainly not prepared to handle instruction faults.
164 */170 */
165 if (fixup_exception(regs))171 if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
166 return;172 return;
167 173
168 /*174 /*
@@ -267,7 +273,8 @@ static inline bool is_permission_fault(unsigned int esr) · 98 unmodified lines
267 unsigned int ec = ESR_ELx_EC(esr);273 unsigned int ec = ESR_ELx_EC(esr);
268 unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;274 unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
269 275
270 return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM);276 return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM) ||
277 (ec == ESR_ELx_EC_IABT_CUR && fsc_type == ESR_ELx_FSC_PERM);
271}278}
272 279
273static bool is_el0_instruction_abort(unsigned int esr)280static bool is_el0_instruction_abort(unsigned int esr)
@@ -312,6 +319,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, · 38 unmodified lines
312 if (regs->orig_addr_limit == KERNEL_DS)319 if (regs->orig_addr_limit == KERNEL_DS)
313 die("Accessing user space memory with fs=KERNEL_DS", regs, esr);320 die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
314 321
322 if (is_el1_instruction_abort(esr))
323 die("Attempting to execute userspace memory", regs, esr);
324
315 if (!search_exception_tables(regs->pc))325 if (!search_exception_tables(regs->pc))
316 die("Accessing user space memory outside uaccess.h routines", regs, esr);326 die("Accessing user space memory outside uaccess.h routines", regs, esr);
317 }327 }