ARM: 6005/1: arm: kprobes: fix register corruption with jprobes

Current implementation of jprobes allocates empty pt_regs from the
stack which is then passed to kprobe_handler() and eventually to
singlestep().  Now when instruction being simulated is STMFD (like
in normal function prologues without CONFIG_FRAME_POINTER), stores
using SP actually write over top of the fabricated pt_regs
structure.

This can be reproduced for example by using LKDTM module:
    # modprobe lkdtm
    # mount -t debugfs none /sys/kernel/debug
    # echo PANIC > /sys/kernel/debug/provoke-crash/INT_HW_IRQ_EN

after this, it fails with corrupted registers (before the requested crash would occur):

lkdtm: Crash point INT_HW_IRQ_EN of type PANIC hit, trigger in 9 rounds
lkdtm: Crash point INT_HW_IRQ_EN of type PANIC hit, trigger in 8 rounds
Internal error: Oops - undefined instruction: 0 [#1]
last sysfs file: /sys/devices/platform/serial8250.0/sleep_timeout
Modules linked in: lkdtm
CPU: 0    Not tainted  (2.6.34-rc2 #69)
PC is at irq_desc+0x1638/0xeeb0
LR is at 0x25
pc : [<c050b428>]    lr : [<00000025>]    psr: c80a0013
sp : ce94bd60  ip : c050b3e8  fp : a0000013
r10: c0aa453c  r9 : cf5d4000  r8 : ce9a1822
r7 : c050b424  r6 : 00000025  r5 : c039d8f8  r4 : c050b3e8
r3 : 00000001  r2 : cf4d0440  r1 : c039d8f8  r0 : 00000020
Flags: NZcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: 8e804019  DAC: 00000015
Process sh (pid: 496, stack limit = 0xce94a2e8)
Stack: (0xce94bd60 to 0xce94c000)
[...]
Code: 000002cd 00000000 00000000 00000001 (dead4ead)
---[ end trace 2b46d5f2b682f370 ]---
Kernel panic - not syncing: Fatal exception in interrupt

This patch allocates enough space (2 * sizeof(struct pt_regs)) from
the stack to prevent such corruption.

Signed-off-by: Mika Westerberg <ext-mika.1.westerberg@nokia.com>
Acked-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Mika Westerberg 2010-03-29 06:59:16 +01:00 committed by Russell King
parent 367d6accea
commit 782a0fd167
1 changed files with 9 additions and 1 deletions

View File

@ -393,6 +393,14 @@ void __kprobes jprobe_return(void)
/* /*
* Setup an empty pt_regs. Fill SP and PC fields as * Setup an empty pt_regs. Fill SP and PC fields as
* they're needed by longjmp_break_handler. * they're needed by longjmp_break_handler.
*
* We allocate some slack between the original SP and start of
* our fabricated regs. To be precise we want to have worst case
* covered which is STMFD with all 16 regs so we allocate 2 *
* sizeof(struct_pt_regs)).
*
* This is to prevent any simulated instruction from writing
* over the regs when they are accessing the stack.
*/ */
"sub sp, %0, %1 \n\t" "sub sp, %0, %1 \n\t"
"ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
@ -410,7 +418,7 @@ void __kprobes jprobe_return(void)
"ldmia sp, {r0 - pc} \n\t" "ldmia sp, {r0 - pc} \n\t"
: :
: "r" (kcb->jprobe_saved_regs.ARM_sp), : "r" (kcb->jprobe_saved_regs.ARM_sp),
"I" (sizeof(struct pt_regs)), "I" (sizeof(struct pt_regs) * 2),
"J" (offsetof(struct pt_regs, ARM_sp)), "J" (offsetof(struct pt_regs, ARM_sp)),
"J" (offsetof(struct pt_regs, ARM_pc)), "J" (offsetof(struct pt_regs, ARM_pc)),
"J" (offsetof(struct pt_regs, ARM_cpsr)) "J" (offsetof(struct pt_regs, ARM_cpsr))