Skip to content

Commit 7419333

Browse files
Pratyush Anandwildea01
authored andcommitted
arm64: kprobe: Always clear pstate.D in breakpoint exception handler
Whenever we are hitting a kprobe from a none-kprobe debug exception handler, we hit an infinite occurrences of "Unexpected kernel single-step exception at EL1" PSTATE.D is debug exception mask bit. It is set whenever we enter into an exception mode. When it is set then Watchpoint, Breakpoint, and Software Step exceptions are masked. However, software Breakpoint Instruction exceptions can never be masked. Therefore, if we ever execute a BRK instruction, irrespective of D-bit setting, we will be receiving a corresponding breakpoint exception. For example: - We are executing kprobe pre/post handler, and kprobe has been inserted in one of the instruction of a function called by handler. So, it executes BRK instruction and we land into the case of KPROBE_REENTER. (This case is already handled by current code) - We are executing uprobe handler or any other BRK handler such as in WARN_ON (BRK BUG_BRK_IMM), and we trace that path using kprobe.So, we enter into kprobe breakpoint handler,from another BRK handler.(This case is not being handled currently) In all such cases kprobe breakpoint exception will be raised when we were already in debug exception mode. SPSR's D bit (bit 9) shows the value of PSTATE.D immediately before the exception was taken. So, in above example cases we would find it set in kprobe breakpoint handler. Single step exception will always be followed by a kprobe breakpoint exception.However, it will only be raised gracefully if we clear D bit while returning from breakpoint exception. If D bit is set then, it results into undefined exception and when it's handler enables dbg then single step exception is generated, however it will never be handled(because address does not match and therefore treated as unexpected). This patch clears D-flag unconditionally in setup_singlestep, so that we can always get single step exception correctly after returning from breakpoint exception. Additionally, it also removes D-flag set statement for KPROBE_REENTER return path, because debug exception for KPROBE_REENTER will always take place in a debug exception state. So, D-flag will already be set in this case. Acked-by: Sandeepa Prabhu <sandeepa.s.prabhu@gmail.com> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Pratyush Anand <panand@redhat.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
1 parent aea73ab commit 7419333

File tree

1 file changed

+13
-16
lines changed

1 file changed

+13
-16
lines changed

arch/arm64/kernel/probes/kprobes.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,18 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
166166
}
167167

168168
/*
169-
* The D-flag (Debug mask) is set (masked) upon debug exception entry.
170-
* Kprobes needs to clear (unmask) D-flag -ONLY- in case of recursive
171-
* probe i.e. when probe hit from kprobe handler context upon
172-
* executing the pre/post handlers. In this case we return with
173-
* D-flag clear so that single-stepping can be carried-out.
174-
*
175-
* Leave D-flag set in all other cases.
169+
* When PSTATE.D is set (masked), then software step exceptions can not be
170+
* generated.
171+
* SPSR's D bit shows the value of PSTATE.D immediately before the
172+
* exception was taken. PSTATE.D is set while entering into any exception
173+
* mode, however software clears it for any normal (none-debug-exception)
174+
* mode in the exception entry. Therefore, when we are entering into kprobe
175+
* breakpoint handler from any normal mode then SPSR.D bit is already
176+
* cleared, however it is set when we are entering from any debug exception
177+
* mode.
178+
* Since we always need to generate single step exception after a kprobe
179+
* breakpoint exception therefore we need to clear it unconditionally, when
180+
* we become sure that the current breakpoint exception is for kprobe.
176181
*/
177182
static void __kprobes
178183
spsr_set_debug_flag(struct pt_regs *regs, int mask)
@@ -245,10 +250,7 @@ static void __kprobes setup_singlestep(struct kprobe *p,
245250

246251
set_ss_context(kcb, slot); /* mark pending ss */
247252

248-
if (kcb->kprobe_status == KPROBE_REENTER)
249-
spsr_set_debug_flag(regs, 0);
250-
else
251-
WARN_ON(regs->pstate & PSR_D_BIT);
253+
spsr_set_debug_flag(regs, 0);
252254

253255
/* IRQs and single stepping do not mix well. */
254256
kprobes_save_local_irqflag(kcb, regs);
@@ -333,8 +335,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
333335
BUG();
334336

335337
kernel_disable_single_step();
336-
if (kcb->kprobe_status == KPROBE_REENTER)
337-
spsr_set_debug_flag(regs, 1);
338338

339339
if (kcb->kprobe_status == KPROBE_REENTER)
340340
restore_previous_kprobe(kcb);
@@ -457,9 +457,6 @@ kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
457457
kprobes_restore_local_irqflag(kcb, regs);
458458
kernel_disable_single_step();
459459

460-
if (kcb->kprobe_status == KPROBE_REENTER)
461-
spsr_set_debug_flag(regs, 1);
462-
463460
post_kprobe_handler(kcb, regs);
464461
}
465462

0 commit comments

Comments
 (0)