Skip to content

Commit

Permalink
parisc: add kernel stack overflow check
Browse files Browse the repository at this point in the history
Add the CONFIG_DEBUG_STACKOVERFLOW config option to enable checks to
detect kernel stack overflows.

Stack overflows can not be detected reliable since we do not want to
introduce too much overhead.

Instead, during irq processing in do_cpu_irq_mask() we check kernel
stack usage of the interrupted kernel process. Kernel threads can be
easily detected by checking the value of space register 7 (sr7) which
is zero when running inside the kernel.

Since THREAD_SIZE is 16k and PAGE_SIZE is 4k, reduce the alignment of
the init thread to the lower value (PAGE_SIZE) in the kernel
vmlinux.ld.S linker script.

Signed-off-by: Helge Deller <deller@gmx.de>
  • Loading branch information
Helge Deller committed May 7, 2013
1 parent c207a76 commit 9372450
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 4 deletions.
11 changes: 11 additions & 0 deletions arch/parisc/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@ config DEBUG_RODATA
If in doubt, say "N".

endmenu

config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
default y
depends on DEBUG_KERNEL
---help---
Say Y here if you want to check the overflows of kernel, IRQ
and exception stacks. This option will cause messages of the
stacks in detail when free stack space drops below a certain
limit.
If in doubt, say "N".
2 changes: 1 addition & 1 deletion arch/parisc/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct thread_info {

/* thread information allocation */

#define THREAD_SIZE_ORDER 2
#define THREAD_SIZE_ORDER 2 /* PA-RISC requires at least 16k stack */
/* Be sure to hunt all references to this down when you change the size of
* the kernel stack */
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
Expand Down
31 changes: 29 additions & 2 deletions arch/parisc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,34 @@ static inline int eirr_to_irq(unsigned long eirr)
return (BITS_PER_LONG - bit) + TIMER_IRQ;
}

int sysctl_panic_on_stackoverflow = 1;

static inline void stack_overflow_check(struct pt_regs *regs)
{
#ifdef CONFIG_DEBUG_STACKOVERFLOW
#define STACK_MARGIN (256*6)

/* Our stack starts directly behind the thread_info struct. */
unsigned long stack_start = (unsigned long) current_thread_info();
unsigned long sp = regs->gr[30];

/* if sr7 != 0, we interrupted a userspace process which we do not want
* to check for stack overflow. We will only check the kernel stack. */
if (regs->sr[7])
return;

if (likely((sp - stack_start) < (THREAD_SIZE - STACK_MARGIN)))
return;

pr_emerg("stackcheck: %s will most likely overflow kernel stack "
"(sp:%lx, stk bottom-top:%lx-%lx)\n",
current->comm, sp, stack_start, stack_start + THREAD_SIZE);

if (sysctl_panic_on_stackoverflow)
panic("low stack detected by irq handler - check messages\n");
#endif
}

/* ONLY called from entry.S:intr_extint() */
void do_cpu_irq_mask(struct pt_regs *regs)
{
Expand Down Expand Up @@ -364,6 +392,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
goto set_out;
}
#endif
stack_overflow_check(regs);
generic_handle_irq(irq);

out:
Expand Down Expand Up @@ -420,6 +449,4 @@ void __init init_IRQ(void)
cpu_eiem = EIEM_MASK(TIMER_IRQ);
#endif
set_eiem(cpu_eiem); /* EIEM : enable all external intr */

}

2 changes: 1 addition & 1 deletion arch/parisc/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ SECTIONS
NOTES

/* Data */
RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, PAGE_SIZE)

/* PA-RISC locks requires 16-byte alignment */
. = ALIGN(16);
Expand Down

0 comments on commit 9372450

Please sign in to comment.