Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: stack unwinding: avoid indefinite looping

Currently stack unwinder is a while(1) loop which relies on the dwarf
unwinder to signal termination, which in turn relies on dwarf info to do
so. This in theory could cause an infinite loop if the dwarf info was
somehow messed up or the register contents were etc.

This fix thus detects the excessive looping and breaks the loop.

| Mem: 26184K used, 1009136K free, 0K shrd, 0K buff, 14416K cached
| CPU: 0.0% usr 72.8% sys 0.0% nic 27.1% idle 0.0% io 0.0% irq 0.0% sirq
| Load average: 4.33 2.60 1.11 2/74 139
| PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
| 133 2 root SWN 0 0.0 3 22.9 [rcu_torture_rea]
| 132 2 root SWN 0 0.0 0 22.0 [rcu_torture_rea]
| 131 2 root SWN 0 0.0 3 21.5 [rcu_torture_rea]
| 126 2 root RW 0 0.0 2 5.4 [rcu_torture_wri]
| 129 2 root SWN 0 0.0 0 0.2 [rcu_torture_fak]
| 137 2 root SW 0 0.0 0 0.2 [rcu_torture_cbf]
| 127 2 root SWN 0 0.0 0 0.1 [rcu_torture_fak]
| 138 115 root R 1464 0.1 2 0.1 top
| 130 2 root SWN 0 0.0 0 0.1 [rcu_torture_fak]
| 128 2 root SWN 0 0.0 0 0.1 [rcu_torture_fak]
| 115 1 root S 1472 0.1 1 0.0 -/bin/sh
| 104 1 root S 1464 0.1 0 0.0 inetd
| 1 0 root S 1456 0.1 2 0.0 init
| 78 1 root S 1456 0.1 0 0.0 syslogd -O /var/log/messages
| 134 2 root SW 0 0.0 2 0.0 [rcu_torture_sta]
| 10 2 root IW 0 0.0 1 0.0 [rcu_preempt]
| 88 2 root IW 0 0.0 1 0.0 [kworker/1:1-eve]
| 66 2 root IW 0 0.0 2 0.0 [kworker/2:2-eve]
| 39 2 root IW 0 0.0 2 0.0 [kworker/2:1-eve]
| unwinder looping too long, aborting !

Cc: <stable@vger.kernel.org>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

+6 -1
+6 -1
arch/arc/kernel/stacktrace.c
··· 112 112 int (*consumer_fn) (unsigned int, void *), void *arg) 113 113 { 114 114 #ifdef CONFIG_ARC_DW2_UNWIND 115 - int ret = 0; 115 + int ret = 0, cnt = 0; 116 116 unsigned int address; 117 117 struct unwind_frame_info frame_info; 118 118 ··· 132 132 break; 133 133 134 134 frame_info.regs.r63 = frame_info.regs.r31; 135 + 136 + if (cnt++ > 128) { 137 + printk("unwinder looping too long, aborting !\n"); 138 + return 0; 139 + } 135 140 } 136 141 137 142 return address; /* return the last address it saw */