redesign sigsetjmp so that signal mask is restored after longjmp

the conventional way to implement sigsetjmp is to save the signal mask
then tail-call to setjmp; siglongjmp then restores the signal mask and
calls longjmp. the problem with this approach is that a signal already
pending, or arriving between unmasking of signals and restoration of
the saved stack pointer, will have its signal handler run on the stack
that was active before siglongjmp was called. this can lead to
unbounded stack usage when siglongjmp is used to leave a signal
handler.

in the new design, sigsetjmp saves its own return address inside the
extended part of the sigjmp_buf (outside the __jmp_buf part used by
setjmp) then calls setjmp to save a jmp_buf inside its own execution.
it then tail-calls to __sigsetjmp_tail, which uses the return value of
setjmp to determine whether to save the current signal mask or restore
a previously-saved mask.

as an added bonus, this design makes it so that siglongjmp and longjmp
are identical. this is useful because the __longjmp_chk function we
need to add for ABI-compatibility assumes siglongjmp and longjmp are
the same, but for different reasons -- it was designed assuming either
can access a flag just past the __jmp_buf indicating whether the
signal masked was saved, and act on that flag. however, early versions
of musl did not have space past the __jmp_buf for the non-sigjmp_buf
version of jmp_buf, so our setjmp cannot store such a flag without
risking clobbering memory on (very) old binaries.
This commit is contained in:
Rich Felker 2015-04-17 21:54:42 -04:00
parent 81e18eb3cd
commit 583e55122e
12 changed files with 177 additions and 133 deletions

View File

@ -4,16 +4,18 @@
.type __sigsetjmp,%function
sigsetjmp:
__sigsetjmp:
str x1,[x0,#176]
cbz x1,setjmp
// TODO errno?
// sigprocmask(SIG_SETMASK, 0, (sigset_t*)buf->__ss);
stp x0,x30,[sp,#-16]!
add x2,x0,#184
mov x1,#0
mov x0,#2
bl sigprocmask
ldp x0,x30,[sp],#16
str lr,[x0,#176]
str x19,[x0,#176+8+8]
mov x19,x0
b setjmp
bl setjmp
mov w1,w0
mov x0,x19
ldr lr,[x0,#176]
ldr x19,[x0,#176+8+8]
.hidden __sigsetjmp_tail
b __sigsetjmp_tail

View File

@ -4,13 +4,19 @@
.type __sigsetjmp,%function
sigsetjmp:
__sigsetjmp:
str a2,[a1,#256]
tst a2,a2
tst r1,r1
beq setjmp
push {a1,lr}
add a3,a1,#260
mov a2,#0
mov a1,#2
bl sigprocmask
pop {a1,lr}
b setjmp
str lr,[r0,#256]
str r4,[r0,#260+8]
mov r4,r0
bl setjmp
mov r1,r0
mov r0,r4
ldr lr,[r0,#256]
ldr r4,[r0,#260+8]
.hidden __sigsetjmp_tail
b __sigsetjmp_tail

View File

@ -4,14 +4,22 @@
.type __sigsetjmp,@function
sigsetjmp:
__sigsetjmp:
mov 4(%esp),%eax
mov 8(%esp),%ecx
mov %ecx,24(%eax)
jecxz 1f
add $28,%eax
push %eax
push $0
push $2
call sigprocmask
add $12,%esp
mov 4(%esp),%eax
popl 24(%eax)
mov %ebx,28+8(%eax)
mov %eax,%ebx
call setjmp
pushl 24(%ebx)
mov %ebx,4(%esp)
mov %eax,8(%esp)
mov 28+8(%ebx),%ebx
.hidden __sigsetjmp_tail
jmp __sigsetjmp_tail
1: jmp setjmp

View File

@ -4,18 +4,18 @@
.type __sigsetjmp,@function
sigsetjmp:
__sigsetjmp:
swi r6, r5, 72
beqi r6, setjmp@PLT
beqi r6, setjmp@PLT
addi r1, r1, -32
swi r15, r1, 28
swi r5, r1, 24
addi r7, r5, 76
add r6, r0, r0
brlid r15, sigprocmask@PLT
ori r5, r0, 2
swi r15,r5,72
swi r19,r5,72+4+8
lwi r15, r1, 28
lwi r5, r1, 24
brid setjmp@PLT
addi r1, r1, 32
brlid r15,setjmp@PLT
ori r19,r5,0
ori r6,r3,0
ori r5,r19,0
lwi r15,r5,72
lwi r19,r5,72+4+8
.hidden __sigsetjmp_tail
bri __sigsetjmp_tail

View File

@ -9,22 +9,25 @@ __sigsetjmp:
lui $gp, %hi(_gp_disp)
addiu $gp, %lo(_gp_disp)
beq $5, $0, 1f
addu $gp, $gp, $25
subu $sp, $sp, 32
sw $4, 20($sp)
sw $ra, 24($sp)
sw $gp, 28($sp)
addu $6, $4, 108
li $5, 0
li $4, 1
sw $4, -4($6)
lw $25, %call16(sigprocmask)($gp)
addu $gp, $gp, $25
sw $ra, 104($4)
sw $16, 104+4+16($4)
lw $25, %call16(setjmp)($gp)
jalr $25
nop
lw $gp, 28($sp)
lw $ra, 24($sp)
lw $4, 20($sp)
addu $sp, $sp, 32
move $16, $4
move $5,$2
move $4,$16
lw $ra, 104($4)
lw $16, 104+4+16($4)
.hidden __sigsetjmp_tail
lw $25, %call16(__sigsetjmp_tail)($gp)
jr $25
nop
1: lw $25, %call16(setjmp)($gp)
jr $25
nop
nop

View File

@ -6,17 +6,18 @@ sigsetjmp:
__sigsetjmp:
l.sfeq r4, r0
l.bf plt(setjmp)
l.sw 52(r3), r4 /* buf->__fl = save */
l.addi r1, r1, -8
l.sw 0(r1), r9
l.sw 4(r1), r3
l.addi r5, r3, 56 /* buf->__ss */
l.add r4, r0, r0
l.jal plt(sigprocmask)
l.ori r3, r0, 2 /* SIG_SETMASK */
l.sw 52(r3), r9
l.sw 52+4+8(r3), r20
l.lwz r9, 0(r1)
l.lwz r3, 4(r1)
l.j plt(setjmp)
l.addi r1, r1, 8
l.jal plt(setjmp)
l.ori r20, r3, 0
l.ori r4, r11, 0
l.ori r3, r20, 0
l.lwz r9, 52(r3)
.hidden __sigsetjmp_tail
l.j plt(__sigsetjmp_tail)
l.lwz r20, 52+4+8(r3)

View File

@ -4,35 +4,23 @@
.type __sigsetjmp,%function
sigsetjmp:
__sigsetjmp:
#int sigsetjmp(sigjmp_buf buf, int save)
# r3 r4
#0) store save into buf->__fl
stw 4, 448(3)
#1) compare save with 0
cmpwi cr7, 4, 0
#2) if its 0, goto setjmp code
beq- cr7, 1f
#3) else: we must call pthread_sigmask(SIG_SETMASK, 0, (sigset_t *)buf->__ss);
# store non-volatile regs 30, 31 into the setjmp buf
stw 30, 0(3)
stw 31, 4(3)
# use them to store the pointer to the jmpbuf and the link reg
mr 30, 3
mflr 31
# put pointer to ss buf into r5 (3rd arg)
addi 5, 3, 452
# put "2" i.e. SIG_SETMASK in r3
li 3, 2
li 4, 0
bl pthread_sigmask
#restore jmpbuf pointer and link reg
mr 3, 30
mtlr 31
#resore non-volatile regs
lwz 30, 0(3)
lwz 31, 4(3)
1:
b setjmp
mflr 5
stw 5, 448(3)
stw 16, 448+4+8(3)
mr 16, 3
bl setjmp
mr 4, 3
mr 3, 16
lwz 5, 448(3)
mtlr 5
lwz 16, 448+4+8(3)
.hidden __sigsetjmp_tail
b __sigsetjmp_tail
1: b setjmp

View File

@ -4,27 +4,37 @@
.type __sigsetjmp,@function
sigsetjmp:
__sigsetjmp:
mov.l r5, @(36,r4)
tst r5, r5
bf 2f
bt 9f
sts.l pr, @-r15
mov.l r4, @-r15
mov r4, r6
add #40, r6
mov #0, r5
mov #2, r4
mov.l L1, r0
bsrf r0
nop
1: mov.l @r15+, r4
lds.l @r15+, pr
add #52, r6
sts pr, r0
mov.l r0, @r6
mov.l r8, @(4+8,r6)
2: mov.l L2, r0
braf r0
mov.l 1f, r0
2: bsrf r0
mov r4, r8
mov r0, r5
mov r8, r4
mov r4, r6
add #52, r6
mov.l @r6, r0
lds r0, pr
mov.l 3f, r0
4: braf r0
mov.l @(4+8,r4), r8
9: mov.l 5f, r0
6: braf r0
nop
3:
.align 2
L1: .long pthread_sigmask@PLT-(1b-.)
L2: .long setjmp@PLT-(3b-.)
1: .long setjmp@PLT-(2b+4-.)
.hidden __sigsetjmp_tail
3: .long __sigsetjmp_tail@PLT-(4b+4-.)
5: .long setjmp@PLT-(6b+4-.)

View File

@ -5,6 +5,5 @@
_Noreturn void siglongjmp(sigjmp_buf buf, int ret)
{
if (buf->__fl) __restore_sigs(buf->__ss);
longjmp(buf, ret);
}

View File

@ -0,0 +1,13 @@
#include <setjmp.h>
#include <signal.h>
#include "syscall.h"
#ifdef SHARED
__attribute__((__visibility__("hidden")))
#endif
int __sigsetjmp_tail(sigjmp_buf jb, int ret)
{
void *p = jb->__ss;
__syscall(SYS_rt_sigprocmask, SIG_SETMASK, ret?p:0, ret?0:p, _NSIG/8);
return ret;
}

View File

@ -1,17 +1,24 @@
/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
.global sigsetjmp
.global __sigsetjmp
.type sigsetjmp,@function
.type __sigsetjmp,@function
sigsetjmp:
__sigsetjmp:
andl %esi,%esi
movq %rsi,64(%rdi)
test %esi,%esi
jz 1f
pushq %rdi
leaq 72(%rdi),%rdx
xorl %esi,%esi
movl $2,%edi
call sigprocmask
popq %rdi
popq 64(%rdi)
mov %rbx,72+8(%rdi)
mov %rdi,%rbx
call setjmp
pushq 64(%rbx)
mov %rbx,%rdi
mov %eax,%esi
mov 72+8(%rbx),%rbx
.hidden __sigsetjmp_tail
jmp __sigsetjmp_tail
1: jmp setjmp

View File

@ -1,17 +1,24 @@
/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
.global sigsetjmp
.global __sigsetjmp
.type sigsetjmp,@function
.type __sigsetjmp,@function
sigsetjmp:
__sigsetjmp:
andl %esi,%esi
movq %rsi,64(%rdi)
test %esi,%esi
jz 1f
pushq %rdi
leaq 72(%rdi),%rdx
xorl %esi,%esi
movl $2,%edi
call sigprocmask
popq %rdi
popq 64(%rdi)
mov %rbx,72+8(%rdi)
mov %rdi,%rbx
call setjmp
pushq 64(%rbx)
mov %rbx,%rdi
mov %eax,%esi
mov 72+8(%rbx),%rbx
.hidden __sigsetjmp_tail
jmp __sigsetjmp_tail
1: jmp setjmp