diff options
author | 2006-11-17 11:14:56 -0800 | |
---|---|---|
committer | 2006-11-17 11:14:56 -0800 | |
commit | 808dbbb6bb61173bf52946a28f99089d2efa4c55 (patch) | |
tree | 4d221ed1e66ea09d244b248bb27998ac2efda119 | |
parent | [PATCH] lockdep: fix static keys in module-allocated percpu areas (diff) | |
download | linux-808dbbb6bb61173bf52946a28f99089d2efa4c55.tar.gz linux-808dbbb6bb61173bf52946a28f99089d2efa4c55.tar.bz2 linux-808dbbb6bb61173bf52946a28f99089d2efa4c55.zip |
x86: be more careful when walking back the frame pointer chain
When showing the stack backtrace, make sure that we never accept not
only an unchanging frame pointer, but also a frame pointer that moves
back down the stack frame. It must always grow up (toward older stack
frames).
I doubt this has triggered, but a subtly corrupt stack with extremely
unlucky contents could cause us to loop forever on a bogus endless frame
pointer chain.
This review was triggered by much worse problems happening in some of
the other stack unwinding code.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/i386/kernel/traps.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 00489b706d27..fe9c5e8e7e6f 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -129,15 +129,19 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, #ifdef CONFIG_FRAME_POINTER while (valid_stack_ptr(tinfo, (void *)ebp)) { + unsigned long new_ebp; addr = *(unsigned long *)(ebp + 4); ops->address(data, addr); /* * break out of recursive entries (such as - * end_of_stack_stop_unwind_function): + * end_of_stack_stop_unwind_function). Also, + * we can never allow a frame pointer to + * move downwards! */ - if (ebp == *(unsigned long *)ebp) + new_ebp = *(unsigned long *)ebp; + if (new_ebp <= ebp) break; - ebp = *(unsigned long *)ebp; + ebp = new_ebp; } #else while (valid_stack_ptr(tinfo, stack)) { |