Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Benjamin Herrenschmidt <benh@kernel.crashing.org>

+23 -18
+1 -3
arch/powerpc/include/asm/processor.h
··· 149 149 150 150 struct thread_struct { 151 151 unsigned long ksp; /* Kernel stack pointer */ 152 - unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */ 153 - 154 152 #ifdef CONFIG_PPC64 155 153 unsigned long ksp_vsid; 156 154 #endif ··· 160 162 #endif 161 163 #ifdef CONFIG_PPC32 162 164 void *pgdir; /* root of page-table tree */ 165 + unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */ 163 166 #endif 164 167 #ifdef CONFIG_PPC_ADV_DEBUG_REGS 165 168 /* ··· 320 321 #else 321 322 #define INIT_THREAD { \ 322 323 .ksp = INIT_SP, \ 323 - .ksp_limit = INIT_SP_LIMIT, \ 324 324 .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ 325 325 .fs = KERNEL_DS, \ 326 326 .fpr = {{0}}, \
+2 -1
arch/powerpc/kernel/asm-offsets.c
··· 80 80 DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr)); 81 81 #else 82 82 DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); 83 + DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16)); 84 + DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit)); 83 85 #endif /* CONFIG_PPC64 */ 84 86 85 87 DEFINE(KSP, offsetof(struct thread_struct, ksp)); 86 - DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit)); 87 88 DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); 88 89 #ifdef CONFIG_BOOKE 89 90 DEFINE(THREAD_NORMSAVES, offsetof(struct thread_struct, normsave[0]));
-12
arch/powerpc/kernel/irq.c
··· 496 496 { 497 497 struct pt_regs *old_regs = set_irq_regs(regs); 498 498 struct thread_info *curtp, *irqtp; 499 - unsigned long saved_sp_limit; 500 499 501 500 /* Switch to the irq stack to handle this */ 502 501 curtp = current_thread_info(); ··· 508 509 return; 509 510 } 510 511 511 - /* Adjust the stack limit */ 512 - saved_sp_limit = current->thread.ksp_limit; 513 - current->thread.ksp_limit = (unsigned long)irqtp + 514 - _ALIGN_UP(sizeof(struct thread_info), 16); 515 - 516 - 517 512 /* Prepare the thread_info in the irq stack */ 518 513 irqtp->task = curtp->task; 519 514 irqtp->flags = 0; ··· 519 526 call_do_irq(regs, irqtp); 520 527 521 528 /* Restore stack limit */ 522 - current->thread.ksp_limit = saved_sp_limit; 523 529 irqtp->task = NULL; 524 530 525 531 /* Copy back updates to the thread_info */ ··· 596 604 static inline void do_softirq_onstack(void) 597 605 { 598 606 struct thread_info *curtp, *irqtp; 599 - unsigned long saved_sp_limit = current->thread.ksp_limit; 600 607 601 608 curtp = current_thread_info(); 602 609 irqtp = softirq_ctx[smp_processor_id()]; 603 610 irqtp->task = curtp->task; 604 611 irqtp->flags = 0; 605 - current->thread.ksp_limit = (unsigned long)irqtp + 606 - _ALIGN_UP(sizeof(struct thread_info), 16); 607 612 call_do_softirq(irqtp); 608 - current->thread.ksp_limit = saved_sp_limit; 609 613 irqtp->task = NULL; 610 614 611 615 /* Set any flag that may have been set on the
+16
arch/powerpc/kernel/misc_32.S
··· 36 36 37 37 .text 38 38 39 + /* 40 + * We store the saved ksp_limit in the unused part 41 + * of the STACK_FRAME_OVERHEAD 42 + */ 39 43 _GLOBAL(call_do_softirq) 40 44 mflr r0 41 45 stw r0,4(r1) 46 + lwz r10,THREAD+KSP_LIMIT(r2) 47 + addi r11,r3,THREAD_INFO_GAP 42 48 stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) 43 49 mr r1,r3 50 + stw r10,8(r1) 51 + stw r11,THREAD+KSP_LIMIT(r2) 44 52 bl __do_softirq 53 + lwz r10,8(r1) 45 54 lwz r1,0(r1) 46 55 lwz r0,4(r1) 56 + stw r10,THREAD+KSP_LIMIT(r2) 47 57 mtlr r0 48 58 blr 49 59 50 60 _GLOBAL(call_do_irq) 51 61 mflr r0 52 62 stw r0,4(r1) 63 + lwz r10,THREAD+KSP_LIMIT(r2) 64 + addi r11,r3,THREAD_INFO_GAP 53 65 stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) 54 66 mr r1,r4 67 + stw r10,8(r1) 68 + stw r11,THREAD+KSP_LIMIT(r2) 55 69 bl __do_irq 70 + lwz r10,8(r1) 56 71 lwz r1,0(r1) 57 72 lwz r0,4(r1) 73 + stw r10,THREAD+KSP_LIMIT(r2) 58 74 mtlr r0 59 75 blr 60 76
+2 -1
arch/powerpc/kernel/process.c
··· 1000 1000 kregs = (struct pt_regs *) sp; 1001 1001 sp -= STACK_FRAME_OVERHEAD; 1002 1002 p->thread.ksp = sp; 1003 + #ifdef CONFIG_PPC32 1003 1004 p->thread.ksp_limit = (unsigned long)task_stack_page(p) + 1004 1005 _ALIGN_UP(sizeof(struct thread_info), 16); 1005 - 1006 + #endif 1006 1007 #ifdef CONFIG_HAVE_HW_BREAKPOINT 1007 1008 p->thread.ptrace_bps[0] = NULL; 1008 1009 #endif
+2 -1
arch/powerpc/lib/sstep.c
··· 1505 1505 */ 1506 1506 if ((ra == 1) && !(regs->msr & MSR_PR) \ 1507 1507 && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) { 1508 + #ifdef CONFIG_PPC32 1508 1509 /* 1509 1510 * Check if we will touch kernel sack overflow 1510 1511 */ ··· 1514 1513 err = -EINVAL; 1515 1514 break; 1516 1515 } 1517 - 1516 + #endif /* CONFIG_PPC32 */ 1518 1517 /* 1519 1518 * Check if we already set since that means we'll 1520 1519 * lose the previous value.