Message ID | 20200703141327.1732550-2-mpe@ellerman.id.au (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [1/5] selftests/powerpc: Add test of stack expansion logic | expand |
Hi Michael, Unfortunately, this patch doesn't completely solve the problem. Trying the original reproducer, I'm still able to trigger the crash even with this patch, although not 100% of the time. (If I turn ASLR off outside of tmux it reliably crashes, if I turn ASLR off _inside_ of tmux it reliably succeeds; all of this is on a serial console.) ./foo 1241000 & sleep 1; killall -USR1 foo; echo ok If I add some debugging information, I see that I'm getting address + 4096 = 7fffffed0fa0 gpr1 = 7fffffed1020 So address + 4096 is 0x80 bytes below the 4k window. I haven't been able to figure out why, gdb gives me a NIP in __kernel_sigtramp_rt64 but I don't know what to make of that. Kind regards, Daniel P.S. I don't know what your policy on linking to kernel bugzilla is, but if you want: Link: https://bugzilla.kernel.org/show_bug.cgi?id=205183 > Reported-by: Tom Lane <tgl@sss.pgh.pa.us> > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > --- > arch/powerpc/mm/fault.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c > index 641fc5f3d7dd..ed01329dd12b 100644 > --- a/arch/powerpc/mm/fault.c > +++ b/arch/powerpc/mm/fault.c > @@ -274,7 +274,7 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address, > /* > * N.B. The POWER/Open ABI allows programs to access up to > * 288 bytes below the stack pointer. > - * The kernel signal delivery code writes up to about 1.5kB > + * The kernel signal delivery code writes up to 4KB > * below the stack pointer (r1) before decrementing it. > * The exec code can write slightly over 640kB to the stack > * before setting the user r1. Thus we allow the stack to > @@ -299,7 +299,7 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address, > * between the last mapped region and the stack will > * expand the stack rather than segfaulting. > */ > - if (address + 2048 >= uregs->gpr[1]) > + if (address + 4096 >= uregs->gpr[1]) > return false; > > if ((flags & FAULT_FLAG_WRITE) && (flags & FAULT_FLAG_USER) && > -- > 2.25.1
Daniel Axtens <dja@axtens.net> writes: > Hi Michael, > > Unfortunately, this patch doesn't completely solve the problem. > > Trying the original reproducer, I'm still able to trigger the crash even > with this patch, although not 100% of the time. (If I turn ASLR off > outside of tmux it reliably crashes, if I turn ASLR off _inside_ of tmux > it reliably succeeds; all of this is on a serial console.) > > ./foo 1241000 & sleep 1; killall -USR1 foo; echo ok > > If I add some debugging information, I see that I'm getting > address + 4096 = 7fffffed0fa0 > gpr1 = 7fffffed1020 > > So address + 4096 is 0x80 bytes below the 4k window. I haven't been able > to figure out why, gdb gives me a NIP in __kernel_sigtramp_rt64 but I > don't know what to make of that. Thanks for testing. I looked at it again this morning and it's fairly obvious when it's not 11pm :) We need space for struct rt_sigframe as well as another 128 bytes, which is __SIGNAL_FRAMESIZE. It's actually mentioned in the comment above struct rt_sigframe. I'll send a v2. > P.S. I don't know what your policy on linking to kernel bugzilla is, but > if you want: > > Link: https://bugzilla.kernel.org/show_bug.cgi?id=205183 In general I prefer to keep things clean with just a single Link: tag pointing to the archive of the patch submission. That can then contain further links and other info, and has the advantage that people can reply to the patch submission in the future to add information to the thread that wasn't known at the time of the commit. cheers
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 641fc5f3d7dd..ed01329dd12b 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -274,7 +274,7 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address, /* * N.B. The POWER/Open ABI allows programs to access up to * 288 bytes below the stack pointer. - * The kernel signal delivery code writes up to about 1.5kB + * The kernel signal delivery code writes up to 4KB * below the stack pointer (r1) before decrementing it. * The exec code can write slightly over 640kB to the stack * before setting the user r1. Thus we allow the stack to @@ -299,7 +299,7 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address, * between the last mapped region and the stack will * expand the stack rather than segfaulting. */ - if (address + 2048 >= uregs->gpr[1]) + if (address + 4096 >= uregs->gpr[1]) return false; if ((flags & FAULT_FLAG_WRITE) && (flags & FAULT_FLAG_USER) &&
We have powerpc specific logic in our page fault handling to decide if an access to an unmapped address below the stack pointer should expand the stack VMA. The code was originally added in 2004 "ported from 2.4". The rough logic is that the stack is allowed to grow to 1MB with no extra checking. Over 1MB the access must be within 2048 bytes of the stack pointer, or be from a user instruction that updates the stack pointer. The 2048 byte allowance below the stack pointer is there to cover the 288 "red zone" as well as the "about 1.5kB" needed by the signal delivery code. Unfortunately since then the signal frame has expanded, and is now 4096 bytes on 64-bit kernels with transactional memory enabled. This means if a process has consumed more than 1MB of stack, and its stack pointer lies less than 4096 bytes from the next page boundary, signal delivery will fault when trying to expand the stack and the process will see a SEGV. The 2048 allowance was sufficient until 2008 as the signal frame was: struct rt_sigframe { struct ucontext uc; /* 0 1440 */ /* --- cacheline 11 boundary (1408 bytes) was 32 bytes ago --- */ long unsigned int _unused[2]; /* 1440 16 */ unsigned int tramp[6]; /* 1456 24 */ struct siginfo * pinfo; /* 1480 8 */ void * puc; /* 1488 8 */ struct siginfo info; /* 1496 128 */ /* --- cacheline 12 boundary (1536 bytes) was 88 bytes ago --- */ char abigap[288]; /* 1624 288 */ /* size: 1920, cachelines: 15, members: 7 */ /* padding: 8 */ }; Then in commit ce48b2100785 ("powerpc: Add VSX context save/restore, ptrace and signal support") (Jul 2008) the signal frame expanded to 2176 bytes: struct rt_sigframe { struct ucontext uc; /* 0 1696 */ <-- /* --- cacheline 13 boundary (1664 bytes) was 32 bytes ago --- */ long unsigned int _unused[2]; /* 1696 16 */ unsigned int tramp[6]; /* 1712 24 */ struct siginfo * pinfo; /* 1736 8 */ void * puc; /* 1744 8 */ struct siginfo info; /* 1752 128 */ /* --- cacheline 14 boundary (1792 bytes) was 88 bytes ago --- */ char abigap[288]; /* 1880 288 */ /* size: 2176, cachelines: 17, members: 7 */ /* padding: 8 */ }; At this point we should have been exposed to the bug, though as far as I know it was never reported. I no longer have a system old enough to easily test on. Then in 2010 commit 320b2b8de126 ("mm: keep a guard page below a grow-down stack segment") caused our stack expansion code to never trigger, as there was always a VMA found for a write up to PAGE_SIZE below r1. That meant the bug was hidden as we continued to expand the signal frame in commit 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context") (Feb 2013): struct rt_sigframe { struct ucontext uc; /* 0 1696 */ /* --- cacheline 13 boundary (1664 bytes) was 32 bytes ago --- */ struct ucontext uc_transact; /* 1696 1696 */ <-- /* --- cacheline 26 boundary (3328 bytes) was 64 bytes ago --- */ long unsigned int _unused[2]; /* 3392 16 */ unsigned int tramp[6]; /* 3408 24 */ struct siginfo * pinfo; /* 3432 8 */ void * puc; /* 3440 8 */ struct siginfo info; /* 3448 128 */ /* --- cacheline 27 boundary (3456 bytes) was 120 bytes ago --- */ char abigap[288]; /* 3576 288 */ /* size: 3872, cachelines: 31, members: 8 */ /* padding: 8 */ /* last cacheline: 32 bytes */ }; And commit 573ebfa6601f ("powerpc: Increase stack redzone for 64-bit userspace to 512 bytes") (Feb 2014): struct rt_sigframe { struct ucontext uc; /* 0 1696 */ /* --- cacheline 13 boundary (1664 bytes) was 32 bytes ago --- */ struct ucontext uc_transact; /* 1696 1696 */ /* --- cacheline 26 boundary (3328 bytes) was 64 bytes ago --- */ long unsigned int _unused[2]; /* 3392 16 */ unsigned int tramp[6]; /* 3408 24 */ struct siginfo * pinfo; /* 3432 8 */ void * puc; /* 3440 8 */ struct siginfo info; /* 3448 128 */ /* --- cacheline 27 boundary (3456 bytes) was 120 bytes ago --- */ char abigap[512]; /* 3576 512 */ <-- /* size: 4096, cachelines: 32, members: 8 */ /* padding: 8 */ }; Then finally in 2017 commit 1be7107fbe18 ("mm: larger stack guard gap, between vmas") exposed us to the existing bug, because it changed the stack VMA to be the correct/real size, meaning our stack expansion code is now triggered. Fix it by increasing the allowance to 4096 bytes. Hard-coding 4096 is obviously unsafe against future expansions of the signal frame in the same way as the existing code. We can't easily use sizeof() because the signal frame structure is not in a header. We will either fix that, or rip out all the custom stack expansion checking logic entirely. Reported-by: Tom Lane <tgl@sss.pgh.pa.us> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> --- arch/powerpc/mm/fault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)