[PATCH 4.9.y] arm: kprobes: Allow to handle reentered kprobe on single-stepping

2021-03-03 Thread ShaoBo Huang
From: Masami Hiramatsu 

commit f3fbd7ec62dec1528fb8044034e2885f2b257941 upstream

This is arm port of commit 6a5022a56ac3 ("kprobes/x86: Allow to
handle reentered kprobe on single-stepping")

Since the FIQ handlers can interrupt in the single stepping
(or preparing the single stepping, do_debug etc.), we should
consider a kprobe is hit in the NMI handler. Even in that
case, the kprobe is allowed to be reentered as same as the
kprobes hit in kprobe handlers
(KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE).

The real issue will happen when a kprobe hit while another
reentered kprobe is processing (KPROBE_REENTER), because
we already consumed a saved-area for the previous kprobe.

Signed-off-by: Masami Hiramatsu 
Signed-off-by: Jon Medhurst 
Fixes: 24ba613c9d6c ("ARM kprobes: core code")
Cc: sta...@vger.kernel.org #v2.6.25~v4.11
Signed-off-by: huangshaobo 
---
 arch/arm/probes/kprobes/core.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 3eb018fa1a1f..c3362ddd6c4c 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -270,6 +270,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
switch (kcb->kprobe_status) {
case KPROBE_HIT_ACTIVE:
case KPROBE_HIT_SSDONE:
+   case KPROBE_HIT_SS:
/* A pre- or post-handler probe got us here. */
kprobes_inc_nmissed_count(p);
save_previous_kprobe(kcb);
@@ -278,6 +279,11 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
singlestep(p, regs, kcb);
restore_previous_kprobe(kcb);
break;
+   case KPROBE_REENTER:
+   /* A nested probe was hit in FIQ, it is a BUG */
+   pr_warn("Unrecoverable kprobe detected at 
%p.\n",
+   p->addr);
+   /* fall through */
default:
/* impossible cases */
BUG();
-- 
2.12.3



Re: [PATCH 4.4.y] arm: kprobes: Allow to handle reentered kprobe on single-stepping

2021-03-01 Thread Shaobo Huang
On March 1, 2021 at 11:30 AM, Greg KH wrote:
> On Mon, Feb 27, 2021 at 05:17:01PM +0800, huangshaobo wrote:
> > From: Masami Hiramatsu 
> > 
> > commit f3fbd7ec62dec1528fb8044034e2885f2b257941 upstream
> > 
> > This is arm port of commit 6a5022a56ac3 ("kprobes/x86: Allow to handle 
> > reentered kprobe on single-stepping")
> > 
> > Since the FIQ handlers can interrupt in the single stepping (or 
> > preparing the single stepping, do_debug etc.), we should consider a 
> > kprobe is hit in the NMI handler. Even in that case, the kprobe is 
> > allowed to be reentered as same as the kprobes hit in kprobe handlers 
> > (KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE).
> > 
> > The real issue will happen when a kprobe hit while another reentered 
> > kprobe is processing (KPROBE_REENTER), because we already consumed a 
> > saved-area for the previous kprobe.
> > 
> > Signed-off-by: Masami Hiramatsu 
> > Signed-off-by: Jon Medhurst 
> > Fixes: 24ba613c9d6c ("ARM kprobes: core code")
> > Cc: sta...@vger.kernel.org #v2.6.25~v4.11
> > Signed-off-by: huangshaobo 
> > ---
> >  arch/arm/probes/kprobes/core.c | 6 ++
> >  1 file changed, 6 insertions(+)
> 
> What about the 4.9.y tree as well?
> 
> thanks,
> 
> greg k-h

Yes, I tested on the 4.4.y tree. From the code analysis, the same problem
exists in the 2.6.25 to 4.11 trees, and of course the 4.9.y tree is also
included.

thanks,
ShaoBo Huang


Re: [PATCH 4.4.y] arm: kprobes: Allow to handle reentered kprobe on single-stepping

2021-02-27 Thread Shaobo Huang
> 
> From: Masami Hiramatsu 
> 
> commit f3fbd7ec62dec1528fb8044034e2885f2b257941 upstream
> 
> This is arm port of commit 6a5022a56ac3 ("kprobes/x86: Allow to
> handle reentered kprobe on single-stepping")
> 
> Since the FIQ handlers can interrupt in the single stepping
> (or preparing the single stepping, do_debug etc.), we should
> consider a kprobe is hit in the NMI handler. Even in that
> case, the kprobe is allowed to be reentered as same as the
> kprobes hit in kprobe handlers
> (KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE).
> 
> The real issue will happen when a kprobe hit while another
> reentered kprobe is processing (KPROBE_REENTER), because
> we already consumed a saved-area for the previous kprobe.
> 
> Signed-off-by: Masami Hiramatsu 
> Signed-off-by: Jon Medhurst 
> Fixes: 24ba613c9d6c ("ARM kprobes: core code")
> Cc: sta...@vger.kernel.org #v2.6.25~v4.11
> Signed-off-by: huangshaobo 

arm32 jprobe does not handle interrupt reentry correctly. When jprobe is
running in singlestep, jprobe is triggered again in system interrupt, it
will run to the BUG function to cause panic.

jprobe needs to enter the kprobe_handler function twice, the first time to
enter kprobe_handler to save the context environment; the second time to
enter kprobe_handler to simulate the replaced instruction and restore the
context environment of the probed function.But the system interrupt is not
closed when the kprobe_handler is entered for the second time in jprobe_return. 
the code of jprobe_return is as follows:
void __kprobes jprobe_return(void)
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
__asm__ __volatile__ (
/*
 * Setup an empty pt_regs. Fill SP and PC fields as
 * 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.
 */
#ifdef CONFIG_THUMB2_KERNEL
...
#else
"subsp, %0, %1  \n\t"
#endif
"ldrr0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
"str%0, [sp, %2]\n\t"
"strr0, [sp, %3]\n\t"
"movr0, sp  \n\t"
"bl kprobe_handler  \n\t"
 
/*
 * Return to the context saved by setjmp_pre_handler
 * and restored by longjmp_break_handler.
 */
#ifdef CONFIG_THUMB2_KERNEL
...
#else
"ldrr0, [sp, %4]\n\t"
"msrcpsr_cxsf, r0   \n\t"
"ldmia  sp, {r0 - pc}   \n\t"
#endif
:
: "r" (kcb->jprobe_saved_regs.ARM_sp),
  "I" (sizeof(struct pt_regs) * 2),
  "J" (offsetof(struct pt_regs, ARM_sp)),
  "J" (offsetof(struct pt_regs, ARM_pc)),
  "J" (offsetof(struct pt_regs, ARM_cpsr)),
  "J" (offsetof(struct pt_regs, ARM_lr))
: "memory", "cc");
}
If the execution reaches the singlestep, the jprobe status is KPROBE_HIT_SS. 
If an interrupt is generated at this time, and jprobe is triggered again in
the interrupt, jprobe reentry will be generated, at this time 
kcb->kprobe_status==KPROBE_HIT_SS, Enter the default branch to execute the
BUG function, causing the system to panic. The partial code of kprobe_handler
is as follows:
void __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p, *cur;
struct kprobe_ctlblk *kcb;

kcb = get_kprobe_ctlblk();
cur = kprobe_running();

#ifdef CONFIG_THUMB2_KERNEL
/*
 * First look for a probe which was registered using an address with
 * bit 0 set, this is the usual situation for pointers to Thumb code.
 * If not found, fallback to looking for one with bit 0 clear.
 */
p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1));
if (!p)
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);

#else /* ! CONFIG_THUMB2_KERNEL */
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
#endif

if (p) {
if (cur) {
/* Kprobe is pending, so we're recursing. */
switch (kcb->kprobe_status) {
case KPROBE_HIT_ACTIVE:
case KPROBE_HIT_SSDONE:
/* A pre- or post-handler probe got us here. */
kprobes_inc_nmissed_count(p);

[PATCH] ARM: fix panic when kasan and kprobe are enabled

2021-02-09 Thread Shaobo Huang
From: huangshaobo 

arm32 uses software to simulate the instruction replaced
by kprobe. some instructions may be simulated by constructing
assembly functions. therefore, before executing instruction
simulation, it is necessary to construct assembly function
execution environment in C language through binding registers.
after kasan is enabled, the register binding relationship will
be destroyed, resulting in instruction simulation errors and
causing kernel panic.

the kprobe emulate instruction function is distributed in three
files: actions-common.c actions-arm.c actions-thumb.c, so disable
KASAN when compiling these files.

for example, use kprobe insert on cap_capable+20 after kasan
enabled, the cap_capable assembly code is as follows:
:
e92d47f0push{r4, r5, r6, r7, r8, r9, sl, lr}
e1a05000mov r5, r0
e280006cadd r0, r0, #108; 0x6c
e1a04001mov r4, r1
e1a06002mov r6, r2
e59fa090ldr sl, [pc, #144]  ;
ebfc7bf8bl  c03aa4b4 <__asan_load4>
e595706cldr r7, [r5, #108]  ; 0x6c
e2859014add r9, r5, #20
..
The emulate_ldr assembly code after enabling kasan is as follows:
c06f1384 :
e92d47f0push{r4, r5, r6, r7, r8, r9, sl, lr}
e282803cadd r8, r2, #60 ; 0x3c
e1a05000mov r5, r0
e7e37855ubfxr7, r5, #16, #4
e1a8mov r0, r8
e1a09001mov r9, r1
e1a04002mov r4, r2
ebf35462bl  c03c6530 <__asan_load4>
e357000fcmp r7, #15
e7e36655ubfxr6, r5, #12, #4
e205a00fand sl, r5, #15
0a01beq c06f13bc 
e0840107add r0, r4, r7, lsl #2
ebf3545cbl  c03c6530 <__asan_load4>
e084010aadd r0, r4, sl, lsl #2
ebf3545abl  c03c6530 <__asan_load4>
e2890010add r0, r9, #16
ebf35458bl  c03c6530 <__asan_load4>
e5990010ldr r0, [r9, #16]
e12fff30blx r0
e356000fcm  r6, #15
1a14bne c06f1430 
e1a06000mov r6, r0
e2840040add r0, r4, #64 ; 0x40
..
when running in emulate_ldr to simulate the ldr instruction, panic
occurred, and the log is as follows:
Unable to handle kernel NULL pointer dereference at virtual address
0090
pgd = ecb46400
[0090] *pgd=2e0fa003, *pmd=
Internal error: Oops: 206 [#1] SMP ARM
PC is at cap_capable+0x14/0xb0
LR is at emulate_ldr+0x50/0xc0
psr: 600d0293 sp : ecd63af8  ip : 0004  fp : c0a7c30c
r10:   r9 : c30897f4  r8 : ecd63cd4
r7 : 000f  r6 : 000a  r5 : e59fa090  r4 : ecd63c98
r3 : c06ae294  r2 :   r1 : b7611300  r0 : bf4ec008
Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 32c5387d  Table: 2d546400  DAC: 
Process bash (pid: 1643, stack limit = 0xecd60190)
(cap_capable) from (kprobe_handler+0x218/0x340)
(kprobe_handler) from (kprobe_trap_handler+0x24/0x48)
(kprobe_trap_handler) from (do_undefinstr+0x13c/0x364)
(do_undefinstr) from (__und_svc_finish+0x0/0x30)
(__und_svc_finish) from (cap_capable+0x18/0xb0)
(cap_capable) from (cap_vm_enough_memory+0x38/0x48)
(cap_vm_enough_memory) from
(security_vm_enough_memory_mm+0x48/0x6c)
(security_vm_enough_memory_mm) from
(copy_process.constprop.5+0x16b4/0x25c8)
(copy_process.constprop.5) from (_do_fork+0xe8/0x55c)
(_do_fork) from (SyS_clone+0x1c/0x24)
(SyS_clone) from (__sys_trace_return+0x0/0x10)
Code: 0050a0e1 6c0080e2 0140a0e1 0260a0e1 (f801f0e7)

Fixes: 35aa1df43283 ("ARM kprobes: instruction single-stepping support")
Fixes: 421015713b30 ("ARM: 9017/2: Enable KASan for ARM")
Signed-off-by: huangshaobo 
---
 arch/arm/probes/kprobes/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
index 14db56f49f0a..6159010dac4a 100644
--- a/arch/arm/probes/kprobes/Makefile
+++ b/arch/arm/probes/kprobes/Makefile
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
+KASAN_SANITIZE_actions-common.o := n
+KASAN_SANITIZE_actions-arm.o := n
+KASAN_SANITIZE_actions-thumb.o := n
 obj-$(CONFIG_KPROBES)  += core.o actions-common.o checkers-common.o
 obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
 test-kprobes-objs  := test-core.o
-- 
2.12.3