Skip to content

Commit e04a28d

Browse files
committed
arm64: debug: re-enable irqs before sending breakpoint SIGTRAP
force_sig_info can sleep under an -rt kernel, so attempting to send a breakpoint SIGTRAP with interrupts disabled yields the following BUG: BUG: sleeping function called from invalid context at /kernel-source/kernel/locking/rtmutex.c:917 in_atomic(): 0, irqs_disabled(): 128, pid: 551, name: test.sh CPU: 5 PID: 551 Comm: test.sh Not tainted 4.1.13-rt13 #7 Hardware name: Freescale Layerscape 2085a RDB Board (DT) Call trace: dump_backtrace+0x0/0x128 show_stack+0x24/0x30 dump_stack+0x80/0xa0 ___might_sleep+0x128/0x1a0 rt_spin_lock+0x2c/0x40 force_sig_info+0xcc/0x210 brk_handler.part.2+0x6c/0x80 brk_handler+0xd8/0xe8 do_debug_exception+0x58/0xb8 This patch fixes the problem by ensuring that interrupts are enabled prior to sending the SIGTRAP if they were already enabled in the user context. Reported-by: Yang Shi <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent bcaf669 commit e04a28d

File tree

1 file changed

+22
-26
lines changed

1 file changed

+22
-26
lines changed

arch/arm64/kernel/debug-monitors.c

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,28 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr)
226226
return retval;
227227
}
228228

229+
static void send_user_sigtrap(int si_code)
230+
{
231+
struct pt_regs *regs = current_pt_regs();
232+
siginfo_t info = {
233+
.si_signo = SIGTRAP,
234+
.si_errno = 0,
235+
.si_code = si_code,
236+
.si_addr = (void __user *)instruction_pointer(regs),
237+
};
238+
239+
if (WARN_ON(!user_mode(regs)))
240+
return;
241+
242+
if (interrupts_enabled(regs))
243+
local_irq_enable();
244+
245+
force_sig_info(SIGTRAP, &info, current);
246+
}
247+
229248
static int single_step_handler(unsigned long addr, unsigned int esr,
230249
struct pt_regs *regs)
231250
{
232-
siginfo_t info;
233-
234251
/*
235252
* If we are stepping a pending breakpoint, call the hw_breakpoint
236253
* handler first.
@@ -239,11 +256,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
239256
return 0;
240257

241258
if (user_mode(regs)) {
242-
info.si_signo = SIGTRAP;
243-
info.si_errno = 0;
244-
info.si_code = TRAP_HWBKPT;
245-
info.si_addr = (void __user *)instruction_pointer(regs);
246-
force_sig_info(SIGTRAP, &info, current);
259+
send_user_sigtrap(TRAP_HWBKPT);
247260

248261
/*
249262
* ptrace will disable single step unless explicitly
@@ -307,17 +320,8 @@ static int call_break_hook(struct pt_regs *regs, unsigned int esr)
307320
static int brk_handler(unsigned long addr, unsigned int esr,
308321
struct pt_regs *regs)
309322
{
310-
siginfo_t info;
311-
312323
if (user_mode(regs)) {
313-
info = (siginfo_t) {
314-
.si_signo = SIGTRAP,
315-
.si_errno = 0,
316-
.si_code = TRAP_BRKPT,
317-
.si_addr = (void __user *)instruction_pointer(regs),
318-
};
319-
320-
force_sig_info(SIGTRAP, &info, current);
324+
send_user_sigtrap(TRAP_BRKPT);
321325
} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
322326
pr_warning("Unexpected kernel BRK exception at EL1\n");
323327
return -EFAULT;
@@ -328,7 +332,6 @@ static int brk_handler(unsigned long addr, unsigned int esr,
328332

329333
int aarch32_break_handler(struct pt_regs *regs)
330334
{
331-
siginfo_t info;
332335
u32 arm_instr;
333336
u16 thumb_instr;
334337
bool bp = false;
@@ -359,14 +362,7 @@ int aarch32_break_handler(struct pt_regs *regs)
359362
if (!bp)
360363
return -EFAULT;
361364

362-
info = (siginfo_t) {
363-
.si_signo = SIGTRAP,
364-
.si_errno = 0,
365-
.si_code = TRAP_BRKPT,
366-
.si_addr = pc,
367-
};
368-
369-
force_sig_info(SIGTRAP, &info, current);
365+
send_user_sigtrap(TRAP_BRKPT);
370366
return 0;
371367
}
372368

0 commit comments

Comments
 (0)