Skip to content

Commit

Permalink
[ARM] 5558/1: Add extra checks to ARM unwinder to avoid tracing corru…
Browse files Browse the repository at this point in the history
…pt stacks

There are situations where the unwinder goes beyond stack boundaries and
unwinds random data. This patch moves the stack boundaries check after
the unwind_exec_insn() call and adds an extra check for possible
infinite loops (like "mov pc, lr" with pc == lr).

The patch also fixes a bug in the unwind instructions interpreter. The
0xb0 instruction can only set PC to LR if this wasn't already set by
a previous instruction (this is used on exceptions taken while in kernel
mode where svc_entry is annotated with ".save {r0 - pc}").

Tested-by: Tony Lindgren <tony@atomide.com>

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Catalin Marinas authored and Russell King committed Jun 19, 2009
1 parent 7436127 commit c894ed6
Showing 1 changed file with 9 additions and 10 deletions.
19 changes: 9 additions & 10 deletions arch/arm/kernel/unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
ctrl->vrs[14] = *vsp++;
ctrl->vrs[SP] = (unsigned long)vsp;
} else if (insn == 0xb0) {
ctrl->vrs[PC] = ctrl->vrs[LR];
if (ctrl->vrs[PC] == 0)
ctrl->vrs[PC] = ctrl->vrs[LR];
/* no further processing */
ctrl->entries = 0;
} else if (insn == 0xb1) {
Expand Down Expand Up @@ -309,18 +310,20 @@ int unwind_frame(struct stackframe *frame)
}

while (ctrl.entries > 0) {
int urc;

if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
return -URC_FAILURE;
urc = unwind_exec_insn(&ctrl);
int urc = unwind_exec_insn(&ctrl);
if (urc < 0)
return urc;
if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
return -URC_FAILURE;
}

if (ctrl.vrs[PC] == 0)
ctrl.vrs[PC] = ctrl.vrs[LR];

/* check for infinite loop */
if (frame->pc == ctrl.vrs[PC])
return -URC_FAILURE;

frame->fp = ctrl.vrs[FP];
frame->sp = ctrl.vrs[SP];
frame->lr = ctrl.vrs[LR];
Expand All @@ -332,7 +335,6 @@ int unwind_frame(struct stackframe *frame)
void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
struct stackframe frame;
unsigned long high, low;
register unsigned long current_sp asm ("sp");

pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
Expand Down Expand Up @@ -362,9 +364,6 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.pc = thread_saved_pc(tsk);
}

low = frame.sp & ~(THREAD_SIZE - 1);
high = low + THREAD_SIZE;

while (1) {
int urc;
unsigned long where = frame.pc;
Expand Down

0 comments on commit c894ed6

Please sign in to comment.