[Lguest] [PATCH] Fix out-by-one error in traps.c

Linus Torvalds torvalds at linux-foundation.org
Sat Sep 1 04:24:54 EST 2007



On Sat, 1 Sep 2007, Rusty Russell wrote:
> 
> This is only for the initial booting stack (init_thread_union); see
> arch/i386/kernel/head.S:
> 	/* Set up the stack pointer */
> 	lss stack_start,%esp
> 	...
> 	pushl $0		# fake return address for unwinder

Ok, we should fix that. We should just make it look like all other stack 
frames.

There is other code in the kernel that "knows" that all kernel stacks have 
the fields for the user stack return on it, namely the ptrace code etc. 
Now, the initial stack is hopefully never *accessed* by that kind of code, 
but this kind of special-case code is just wrong.

> > But your patch does improve the sanity checking of the frame pointer. That 
> > said, I think the following patch improves it more: does this also work 
> > for you? (Totally untested, but it looks like the RightThing(tm) to do)
> 
> Yes, looks good.  Perhaps one additional magic num removal:

Well, we might as well then just make the code readable instead. IOW, how 
about this one, which just declares a structure that describes the stack 
frame thing? That just makes everything clearer, since we can then use 
"sizeof(that structure)" instead of using the magic "2*sizeof(unsigned 
long)".

		Linus

---
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index cfffe3d..47b0bef 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -100,36 +100,45 @@ asmlinkage void machine_check(void);
 int kstack_depth_to_print = 24;
 static unsigned int code_bytes = 64;
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size)
 {
 	return	p > (void *)tinfo &&
-		p < (void *)tinfo + THREAD_SIZE - 3;
+		p <= (void *)tinfo + THREAD_SIZE - size;
 }
 
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+	struct stack_frame *next_frame;
+	unsigned long return_address;
+};
+
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
 				unsigned long *stack, unsigned long ebp,
 				struct stacktrace_ops *ops, void *data)
 {
-	unsigned long addr;
-
 #ifdef	CONFIG_FRAME_POINTER
-	while (valid_stack_ptr(tinfo, (void *)ebp)) {
-		unsigned long new_ebp;
-		addr = *(unsigned long *)(ebp + 4);
+	struct stack_frame *frame = (struct stack_frame *)ebp;
+	while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) {
+		struct stack_frame *next;
+		unsigned long addr;
+
+		addr = frame->return_address;
 		ops->address(data, addr);
 		/*
 		 * break out of recursive entries (such as
 		 * end_of_stack_stop_unwind_function). Also,
 		 * we can never allow a frame pointer to
 		 * move downwards!
-	 	 */
-	 	new_ebp = *(unsigned long *)ebp;
-		if (new_ebp <= ebp)
+		 */
+		next = frame->next_frame;
+		if (next <= frame)
 			break;
-		ebp = new_ebp;
+		frame = next;
 	}
 #else
-	while (valid_stack_ptr(tinfo, stack)) {
+	while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
+		unsigned long addr;
+
 		addr = *stack++;
 		if (__kernel_text_address(addr))
 			ops->address(data, addr);



More information about the Lguest mailing list