powerpc: Remove ksp_limit on ppc64

We've been keeping that field in thread_struct for a while, it contains
the "limit" of the current stack pointer and is meant to be used for
detecting stack overflows.

It has a few problems however:

 - First, it was never actually *used* on 64-bit. Set and updated but
not actually exploited

 - When switching stack to/from irq and softirq stacks, it's update
is racy unless we hard disable interrupts, which is costly. This
is fine on 32-bit as we don't soft-disable there but not on 64-bit.

Thus rather than fixing 2 in order to implement 1 in some hypothetical
future, let's remove the code completely from 64-bit. In order to avoid
a clutter of ifdef's, we remove the updates from C code completely
during interrupt stack switching, and instead maintain it from the
asm helper that is used to do the stack switching in the first place.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 0366a1c7
...@@ -149,8 +149,6 @@ typedef struct { ...@@ -149,8 +149,6 @@ typedef struct {
struct thread_struct { struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */ unsigned long ksp; /* Kernel stack pointer */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
unsigned long ksp_vsid; unsigned long ksp_vsid;
#endif #endif
...@@ -162,6 +160,7 @@ struct thread_struct { ...@@ -162,6 +160,7 @@ struct thread_struct {
#endif #endif
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
void *pgdir; /* root of page-table tree */ void *pgdir; /* root of page-table tree */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */
#endif #endif
#ifdef CONFIG_PPC_ADV_DEBUG_REGS #ifdef CONFIG_PPC_ADV_DEBUG_REGS
/* /*
...@@ -321,7 +320,6 @@ struct thread_struct { ...@@ -321,7 +320,6 @@ struct thread_struct {
#else #else
#define INIT_THREAD { \ #define INIT_THREAD { \
.ksp = INIT_SP, \ .ksp = INIT_SP, \
.ksp_limit = INIT_SP_LIMIT, \
.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
.fs = KERNEL_DS, \ .fs = KERNEL_DS, \
.fpr = {{0}}, \ .fpr = {{0}}, \
......
...@@ -80,10 +80,11 @@ int main(void) ...@@ -80,10 +80,11 @@ int main(void)
DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr)); DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr));
#else #else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
DEFINE(KSP, offsetof(struct thread_struct, ksp)); DEFINE(KSP, offsetof(struct thread_struct, ksp));
DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
#ifdef CONFIG_BOOKE #ifdef CONFIG_BOOKE
DEFINE(THREAD_NORMSAVES, offsetof(struct thread_struct, normsave[0])); DEFINE(THREAD_NORMSAVES, offsetof(struct thread_struct, normsave[0]));
......
...@@ -496,7 +496,6 @@ void do_IRQ(struct pt_regs *regs) ...@@ -496,7 +496,6 @@ void do_IRQ(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);
struct thread_info *curtp, *irqtp; struct thread_info *curtp, *irqtp;
unsigned long saved_sp_limit;
/* Switch to the irq stack to handle this */ /* Switch to the irq stack to handle this */
curtp = current_thread_info(); curtp = current_thread_info();
...@@ -509,12 +508,6 @@ void do_IRQ(struct pt_regs *regs) ...@@ -509,12 +508,6 @@ void do_IRQ(struct pt_regs *regs)
return; return;
} }
/* Adjust the stack limit */
saved_sp_limit = current->thread.ksp_limit;
current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);
/* Prepare the thread_info in the irq stack */ /* Prepare the thread_info in the irq stack */
irqtp->task = curtp->task; irqtp->task = curtp->task;
irqtp->flags = 0; irqtp->flags = 0;
...@@ -526,7 +519,6 @@ void do_IRQ(struct pt_regs *regs) ...@@ -526,7 +519,6 @@ void do_IRQ(struct pt_regs *regs)
call_do_irq(regs, irqtp); call_do_irq(regs, irqtp);
/* Restore stack limit */ /* Restore stack limit */
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL; irqtp->task = NULL;
/* Copy back updates to the thread_info */ /* Copy back updates to the thread_info */
...@@ -604,16 +596,12 @@ void irq_ctx_init(void) ...@@ -604,16 +596,12 @@ void irq_ctx_init(void)
static inline void do_softirq_onstack(void) static inline void do_softirq_onstack(void)
{ {
struct thread_info *curtp, *irqtp; struct thread_info *curtp, *irqtp;
unsigned long saved_sp_limit = current->thread.ksp_limit;
curtp = current_thread_info(); curtp = current_thread_info();
irqtp = softirq_ctx[smp_processor_id()]; irqtp = softirq_ctx[smp_processor_id()];
irqtp->task = curtp->task; irqtp->task = curtp->task;
irqtp->flags = 0; irqtp->flags = 0;
current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);
call_do_softirq(irqtp); call_do_softirq(irqtp);
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL; irqtp->task = NULL;
/* Set any flag that may have been set on the /* Set any flag that may have been set on the
......
...@@ -36,25 +36,41 @@ ...@@ -36,25 +36,41 @@
.text .text
/*
* We store the saved ksp_limit in the unused part
* of the STACK_FRAME_OVERHEAD
*/
_GLOBAL(call_do_softirq) _GLOBAL(call_do_softirq)
mflr r0 mflr r0
stw r0,4(r1) stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2)
addi r11,r3,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
mr r1,r3 mr r1,r3
stw r10,8(r1)
stw r11,THREAD+KSP_LIMIT(r2)
bl __do_softirq bl __do_softirq
lwz r10,8(r1)
lwz r1,0(r1) lwz r1,0(r1)
lwz r0,4(r1) lwz r0,4(r1)
stw r10,THREAD+KSP_LIMIT(r2)
mtlr r0 mtlr r0
blr blr
_GLOBAL(call_do_irq) _GLOBAL(call_do_irq)
mflr r0 mflr r0
stw r0,4(r1) stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2)
addi r11,r3,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4 mr r1,r4
stw r10,8(r1)
stw r11,THREAD+KSP_LIMIT(r2)
bl __do_irq bl __do_irq
lwz r10,8(r1)
lwz r1,0(r1) lwz r1,0(r1)
lwz r0,4(r1) lwz r0,4(r1)
stw r10,THREAD+KSP_LIMIT(r2)
mtlr r0 mtlr r0
blr blr
......
...@@ -1000,9 +1000,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, ...@@ -1000,9 +1000,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
kregs = (struct pt_regs *) sp; kregs = (struct pt_regs *) sp;
sp -= STACK_FRAME_OVERHEAD; sp -= STACK_FRAME_OVERHEAD;
p->thread.ksp = sp; p->thread.ksp = sp;
#ifdef CONFIG_PPC32
p->thread.ksp_limit = (unsigned long)task_stack_page(p) + p->thread.ksp_limit = (unsigned long)task_stack_page(p) +
_ALIGN_UP(sizeof(struct thread_info), 16); _ALIGN_UP(sizeof(struct thread_info), 16);
#endif
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
p->thread.ptrace_bps[0] = NULL; p->thread.ptrace_bps[0] = NULL;
#endif #endif
......
...@@ -1505,6 +1505,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -1505,6 +1505,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
*/ */
if ((ra == 1) && !(regs->msr & MSR_PR) \ if ((ra == 1) && !(regs->msr & MSR_PR) \
&& (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) { && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) {
#ifdef CONFIG_PPC32
/* /*
* Check if we will touch kernel sack overflow * Check if we will touch kernel sack overflow
*/ */
...@@ -1513,7 +1514,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -1513,7 +1514,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
err = -EINVAL; err = -EINVAL;
break; break;
} }
#endif /* CONFIG_PPC32 */
/* /*
* Check if we already set since that means we'll * Check if we already set since that means we'll
* lose the previous value. * lose the previous value.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment