From d310cbfc37a7494c91b7e58642caff986bf8a948 Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Sun, 12 Oct 2003 21:43:13 -0700 Subject: [PATCH] [PATCH] avoid crashes due to unaligned stacks This fixes the stack end detection properly, and verifies that the stack content printing does not overflow into the next page even partially. This is required especially for x86 BIOSes that misalign the stack, together with the page access debugging that unmaps unused kernel pages to check for valid accesses. Architectures with special needs (eg HPPA with stacks that grow up) can override the kernel stack end test with __HAVE_ARCH_KSTACK_END if they ever enable the anal slab debugging code. --- arch/i386/kernel/traps.c | 4 ++-- include/linux/sched.h | 10 ++++++++++ mm/slab.c | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 3687472948ecc..fa0f7505f1028 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -104,7 +104,7 @@ void show_trace(struct task_struct *task, unsigned long * stack) #ifdef CONFIG_KALLSYMS printk("\n"); #endif - while (((long) stack & (THREAD_SIZE-4)) != 0) { + while (!kstack_end(stack)) { addr = *stack++; if (kernel_text_address(addr)) { printk(" [<%08lx>] ", addr); @@ -138,7 +138,7 @@ void show_stack(struct task_struct *task, unsigned long *esp) stack = esp; for(i = 0; i < kstack_depth_to_print; i++) { - if (((long) stack & (THREAD_SIZE-4)) == 0) + if (kstack_end(stack)) break; if (i && ((i % 8) == 0)) printk("\n "); diff --git a/include/linux/sched.h b/include/linux/sched.h index a15d95aa34b5c..4241be4f518f8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -541,6 +541,16 @@ union thread_union { unsigned long stack[INIT_THREAD_SIZE/sizeof(long)]; }; +#ifndef __HAVE_ARCH_KSTACK_END +static inline int kstack_end(void *addr) +{ + /* Reliable end of stack detection: + * Some APM bios versions misalign the stack + */ + return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*))); +} +#endif + extern union thread_union init_thread_union; extern struct task_struct init_task; diff --git a/mm/slab.c b/mm/slab.c index 1947a87227ab4..d26829eb67d94 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -862,7 +862,7 @@ static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, unsigned unsigned long *sptr = &caller; unsigned long svalue; - while (((long) sptr & (THREAD_SIZE-4)) != 0) { + while (!kstack_end(sptr)) { svalue = *sptr++; if (kernel_text_address(svalue)) { *addr++=svalue; -- 2.53.0