Skip to contentSkip to conversation

(3/3) stack overflow checking for x86

PATCH In review Dave Hansen 2 participants 3 messages Oct 18, 2002

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 (3/3) stack overflow checking for x86

* stack checking (3/3)
- use gcc's profiling features to check for stack overflows upon entry to functions.
- Warn if the task goes over 4k.
- Panic if the stack gets within 512 bytes of overflowing.
- use kksymoops information, if available

This won't apply cleanly without the irqstack patch, but the conflict is easy to resolve. It requires the thread_info cleanup.

Signature · 2 lines
Dave Hansen
[email protected]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.858.1.2 -> 1.863
# arch/i386/kernel/process.c 1.32.1.1 -> 1.36
# arch/i386/Config.help 1.21.1.2 -> 1.24
# Makefile 1.320.1.1 -> 1.322
# include/asm-i386/thread_info.h 1.10 -> 1.11
# arch/i386/kernel/entry.S 1.38.1.2 -> 1.45
# arch/i386/config.in 1.56.1.4 -> 1.59
# arch/i386/Makefile 1.21.1.1 -> 1.23
# arch/i386/boot/compressed/misc.c 1.9 -> 1.10
# arch/i386/kernel/init_task.c 1.6.1.1 -> 1.8
# arch/i386/kernel/i386_ksyms.c 1.34.1.2 -> 1.36
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/16 haveblue@elm3b96.(none) 1.861

# change warning semantics
# --------------------------------------------
# 02/10/16	haveblue@elm3b96.(none)	1.862
# entry.S:
#   don't need stack_warn_lock anymore
# --------------------------------------------
# 02/10/16	haveblue@elm3b96.(none)	1.863
# merge
# --------------------------------------------
#
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Wed Oct 16 14:14:00 2002
+++ b/Makefile	Wed Oct 16 14:14:00 2002
@@ -156,7 +156,8 @@

CPPFLAGS := -D__KERNEL__ -Iinclude
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \

-	  	   -fomit-frame-pointer -fno-strict-aliasing -fno-common
+	  	   -fno-strict-aliasing -fno-common

+
AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)

export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
@@ -255,6 +256,10 @@

ifdef CONFIG_MODULES
export EXPORT_FLAGS := -DEXPORT_SYMTAB
+endif
+
+ifneq ($(CONFIG_FRAME_POINTER),y)
+CFLAGS += -fomit-frame-pointer
endif

#

arch/i386/Config.help +14 -0
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
@@ -1050,6 +1050,20 @@
   symbolic stack backtraces. This increases the size of the kernel
   somewhat, as all symbols have to be loaded into the kernel image.
 
+CONFIG_X86_STACK_CHECK
+  Say Y here to have the kernel attempt to detect when the per-task
+  kernel stack overflows. 
+
+  Some older versions of gcc don't handle the -p option correctly.  
+  Kernprof is affected by the same problem, which is described here:
+  http://oss.sgi.com/projects/kernprof/faq.html#Q9
+
+  Basically, if you get oopses in __free_pages_ok during boot when
+  you have this turned on, you need to fix gcc.  The Redhat 2.96 
+  version and gcc-3.x seem to work.  
+
+  If not debugging a stack overflow problem, say N
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
arch/i386/Makefile +4 -0
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
@@ -49,6 +49,10 @@
 MACHINE	:= mach-generic
 endif
 
+ifdef CONFIG_X86_STACK_CHECK
+CFLAGS += -p
+endif
+
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
arch/i386/boot/compressed/misc.c +4 -0
diff -Nru a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
@@ -377,3 +377,7 @@
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
 	return high_loaded;
 }
+
+/* We don't actually check for stack overflows this early. */
+__asm__(".globl mcount ; mcount: ret\n");
+
arch/i386/config.in +5 -0
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
@@ -467,6 +467,11 @@
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
    bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
+   bool '  Check for stack overflows' CONFIG_X86_STACK_CHECK
+   if [ "$CONFIG_X86_STACK_CHECK" = "y" ]; then
+      define_bool CONFIG_FRAME_POINTER y
+   fi
+
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
arch/i386/kernel/entry.S +55 -0

61 lines not on this page · raw message

arch/i386/kernel/i386_ksyms.c +5 -0
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
@@ -192,3 +192,8 @@
 EXPORT_SYMBOL(is_sony_vaio_laptop);
 
 EXPORT_SYMBOL(__PAGE_KERNEL);
+
+#ifdef CONFIG_X86_STACK_CHECK
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif
arch/i386/kernel/init_task.c +4 -0
diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
@@ -16,6 +16,10 @@
 union thread_union init_irq_union
 	__attribute__((__section__(".data.init_task")));
 
+#ifdef CONFIG_X86_STACK_CHECK
+union thread_union stack_overflow_stack
+	__attribute__((__section__(".data.init_task")));
+#endif
 
 /*
  * Initial thread structure.
arch/i386/kernel/process.c +19 -1
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
@@ -156,7 +156,25 @@
 
 __setup("idle=", idle_setup);
 
-void show_regs(struct pt_regs * regs)
+void stack_overflow(unsigned long esp, unsigned long eip)
+{
+	int panicing = ((esp&(THREAD_SIZE-1)) <= STACK_PANIC);
+
+	printk( "esp: 0x%x masked: 0x%x STACK_PANIC:0x%x %d %d\n", 
+		esp, (esp&(THREAD_SIZE-1)), STACK_PANIC, (((esp&(THREAD_SIZE-1)) <= STACK_PANIC)), panicing );
+	
+	if (panicing)
+		print_symbol("stack overflow from %s\n", eip);
+	else
+		print_symbol("excessive stack use from %s\n", eip);
+	printk("esp: %p\n", (void*)esp);
+	show_trace((void*)esp);
+	
+	if (panicing)
+		panic("stack overflow\n");
+}
+
+asmlinkage void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
 
include/asm-i386/thread_info.h +2 -0
diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
@@ -60,6 +60,8 @@
  */
 #define THREAD_ORDER 1 
 #define INIT_THREAD_SIZE       THREAD_SIZE
+#define STACK_PANIC		0x200ul
+#define STACK_WARN		((THREAD_SIZE)>>1)
 
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)			\
#1 lore raw
Quoted 8 lines · Dave Hansen

* stack checking (3/3)
- use gcc's profiling features to check for stack overflows upon entry to functions.
- Warn if the task goes over 4k.
- Panic if the stack gets within 512 bytes of overflowing.
- use kksymoops information, if available

This won't apply cleanly without the irqstack patch, but the conflict is easy to resolve. It requires the thread_info cleanup.

Greg KH just pointed out that someone else snuck in an overflow check.
However, they take completely different approaches. The Ben LaHaise
one that I posted uses GCC features to check the stack on entry to all functions. The one in the tree now is much, much simpler than Ben's, but only works only for detecting problems at the time that an interrupt actually occurs.

Signature · 2 lines
Dave Hansen
[email protected]
#2 lore raw
Quoted 6 lines · Dave Hansen

Greg KH just pointed out that someone else snuck in an overflow check.
However, they take completely different approaches. The Ben LaHaise
one that I posted uses GCC features to check the stack on entry to all functions. The one in the tree now is much, much simpler than Ben's, but only works only for detecting problems at the time that an interrupt actually occurs.

Yes, we had that patch in the RH 2.4 kernel, but it didn't detect the stack overflow we spent days to track. Our problem was just one of a really deep stack: RPC-to-network-filesystem-on-ext3-with-htree. This overflowed the 8kB stack even without an interrupt happening.

We fixed the htree and the network filesystem stack usage, but if we added LVM/EVMS into the mix (which we would have in production) and threw in a piggy interrupt handler we would possibly again overflow an 8kB stack, so having a per-entry/exit stack checker would be great.

Cheers, Andreas
--
Andreas Dilger
http://www-mddsp.enel.ucalgary.ca/People/adilger/
http://sourceforge.net/projects/ext2resize/