- UML - fix signal mask on delivery error
PATCH 9/11 - UML - fix signal mask on delivery error
Quoted 1 line
From Bodo Stroesser - If the user stack limit is reached or the
signal stack assigned with sigaltstack() is invalid when a user signal handler with SA_ONSTACK has to be started, the signal mask of the interrupted user program is modified. This happens because the mask, that should be used with the handler only, is written to "current->blocked" even if the handler could not be started. But without a handler, no rewrite of the original mask at sys_sigreturn will be done. A slightly different case is sys_sigsuspend(), where the mask is already modified when kern_do_signal() is started. "*oldset" and "current->blocked" are not equal here and thus current->blocked has to be set to *oldset, if an error occurs in handle_signal(). For both cases I've written small tests, and with the patch the result is OK.
This issue is relevant for other architectures too (e.g. i386, I've seen).
arch/um/kernel/signal_kern.c +8 -4
@@ -79,7 +79,14 @@else err =setup_signal_stack_sc (sp, signr, ka, regs, oldset); -if (!err && !(ka->sa.sa_flags &SA_NODEFER )) { +if (err){ +spin_lock_irq (¤t->sighand->siglock); + current->blocked = *oldset; +recalc_sigpending (); +spin_unlock_irq (¤t->sighand->siglock); +force_sigsegv (signr, current); + } +else if (!(ka->sa.sa_flags &SA_NODEFER )){spin_lock_irq (¤t->sighand->siglock);sigorsets (¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
@@ -87,9 +94,6 @@recalc_sigpending ();spin_unlock_irq (¤t->sighand->siglock); } - -if (err) -force_sigsegv (signr, current); }static int kern_do_signal (struct pt_regs *regs,sigset_t *oldset)
(removed linux-kernel, added linux-arch)
Quoted 16 lines · Jeff Dike
Quoted 2 lines
From Bodo Stroesser - If the user stack limit is reached or the
signal stack assigned with
sigaltstack()is invalid when a user signal handler withSA_ONSTACKhas to be started, the signal mask of the interrupted user program is modified. This happens because the mask, that should be used with the handler only, is written to "current->blocked" even if the handler could not be started. But without a handler, no rewrite of the original mask atsys_sigreturnwill be done. A slightly different case issys_sigsuspend(), where the mask is already modified whenkern_do_signal()is started. "*oldset" and "current->blocked" are not equal here and thuscurrent->blockedhas to be set to *oldset, if an error occurs inhandle_signal(). For both cases I've written small tests, and with the patch the result is OK.
This issue is relevant for other architectures too (e.g. i386, I've seen).
Could you send one of the test apps? This is something which the arch maintainers might want to look into fixing, thanks.
Quoted 32 lines
Signed-off-by Jeff Dike <[email protected]>Index:
2.6.9/arch/um/kernel/signal_kern.c
===================================================================arch/um/kernel/signal_kern.c +8
-4@@ -79,7 +79,14 @@else err =setup_signal_stack_sc (sp, signr, ka, regs, oldset); -if (!err && !(ka->sa.sa_flags &SA_NODEFER )) { +if (err){ +spin_lock_irq (¤t->sighand->siglock); + current->blocked = *oldset; +recalc_sigpending (); +spin_unlock_irq (¤t->sighand->siglock); +force_sigsegv (signr, current); + } +else if (!(ka->sa.sa_flags &SA_NODEFER )){spin_lock_irq (¤t->sighand->siglock);sigorsets (¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);@@ -87,9 +94,6 @@recalc_sigpending ();spin_unlock_irq (¤t->sighand->siglock); } - -if (err) -force_sigsegv (signr, current); }static int kern_do_signal (struct pt_regs *regs,sigset_t *oldset)
Quoted 2 lines · [email protected] said:
Could you send one of the test apps? This is something which the arch maintainers might want to look into fixing, thanks.
Attached...
Included are
breakout.c - UML-specific breakouts, fixed in 2.6 and 2.4 now, but
please don't popularize these :-)
step_sighdlr.c - PTRACE_SINGLESTEPs into a signal handler, if I'm
reading the code right, fails on i386
interrupted_syscall.c - counts signals and system calls during
interrupted system calls, under ptrace and not. Fails on x86 under ptrace.
kernel_restorer.c - I can't get this to compile because it's too
intimate with the libc headers, expecting to get a k_sigaction from them.
sigmasking.c - Makes sure that when a signal is (not) delivered to
a bogus stack, that a segfault is delivered then, and not after returning to userspace. This is the test relevant to the patch that Andrew replied to.
Jeff
Quoted 2 lines · Jeff Dike
step_sighdlr.c-PTRACE_SINGLESTEPsinto a signal handler, if I'm
reading the code right, fails on i386
I haven't looked at this particular test but given the description I think it'll fail on ppc64 too. This ought to fix it for 2.6, along with single-stepping over syscalls and single-stepping over sigreturn (which is a special case).
The 2.4 kernel also has these problems on most arches -- the fixes for this are around, but weren't pushed to Marcelo because they weren't considered a really necessary fix. Was that wrong? Should I dig them out and send them on?
arch/ppc64/kernel/signal.c renamed from arch/ppc64/kernel/signal.c.sstep +4 -0
@@ -26,6 +26,7 @@#include <linux/unistd.h> #include <linux/stddef.h> #include <linux/elf.h> +#include <linux/ptrace.h> #include <asm/sigcontext.h> #include <asm/ucontext.h> #include <asm/uaccess.h>
@@ -439,6 +440,9 @@ static void setup_rt_frame(int signr, stif (err) goto badframe; +if (test_thread_flag (TIF_SINGLESTEP )) +ptrace_notify (SIGTRAP ); +return ; badframe:
arch/ppc64/kernel/entry.S renamed from arch/ppc64/kernel/entry.S.sstep +2 -2
@@ -162,7 +162,7 @@ syscall_error_cont: /* check for syscall tracing or audit */ ld r9,TI_FLAGS(r12) - andi. r0,r9,_TIF_SYSCALL_T_OR_A + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) bne- syscall_exit_trace syscall_exit_trace_cont:
@@ -317,7 +317,7 @@ _GLOBAL(ppc64_rt_sigreturn) blt syscall_exit clrrdi r4,r1,THREAD_SHIFT ld r4,TI_FLAGS(r4) - andi. r4,r4,_TIF_SYSCALL_T_OR_A + andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) beq+ 81f bl .do_syscall_trace_leave 81: b .ret_from_except
arch/ppc64/kernel/ptrace.c renamed from arch/ppc64/kernel/ptrace.c.sstep +2 -1
@@ -318,7 +318,8 @@ void do_syscall_trace_leave(void)if (unlikely (current->audit_context))audit_syscall_exit (current,0 );/* FIXME: pass pt_regs */ -if (test_thread_flag (TIF_SYSCALL_TRACE ) +if ((test_thread_flag (TIF_SYSCALL_TRACE ) + ||test_thread_flag (TIF_SINGLESTEP )) && (current->ptrace &PT_PTRACED ))do_syscall_trace (); }
arch/ppc64/kernel/signal32.c renamed from arch/ppc64/kernel/signal32.c.sstep +7 -0
@@ -25,6 +25,7 @@#include <linux/errno.h> #include <linux/elf.h> #include <linux/compat.h> +#include <linux/ptrace.h> #include <asm/ppc32.h> #include <asm/uaccess.h> #include <asm/ppcdebug.h>
@@ -696,6 +697,9 @@ static void handle_rt_signal32(unsigned regs->trap =0 ; regs->result =0 ; +if (test_thread_flag (TIF_SINGLESTEP )) +ptrace_notify (SIGTRAP ); +return ; badframe:
@@ -859,6 +863,9 @@ static void handle_signal32(unsigned lon regs->trap =0 ; regs->result =0 ; +if (test_thread_flag (TIF_SINGLESTEP )) +ptrace_notify (SIGTRAP ); +return ; badframe:
include/asm-ppc64/ptrace-common.h renamed from include/asm-ppc64/ptrace-common.h.sstep +2 -0
@@ -58,6 +58,7 @@ static inline void set_single_step(strucstruct pt_regs *regs = task->thread.regs;if (regs !=NULL ) regs->msr |=MSR_SE ; +set_ti_thread_flag (task->thread_info,TIF_SINGLESTEP ); }static inline void clear_single_step (struct task_struct *task)
@@ -65,6 +66,7 @@ static inline void clear_single_step(strstruct pt_regs *regs = task->thread.regs;if (regs !=NULL ) regs->msr &= ~MSR_SE ; + clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); }#endif /* _PPC64_PTRACE_COMMON_H */
include/asm-ppc64/thread_info.h renamed from include/asm-ppc64/thread_info.h.sstep +2 -0
@@ -97,6 +97,7 @@ static inline struct thread_info *curren#define TIF_RUN_LIGHT 6/* iSeries run light */ #define TIF_ABI_PENDING 7/* 32/64 bit switch needed */ #define TIF_SYSCALL_AUDIT 8/* syscall auditing active */ +#define TIF_SINGLESTEP 9/* singlestepping active */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -108,6 +109,7 @@ static inline struct thread_info *curren#define _TIF_RUN_LIGHT (1<<TIF_RUN_LIGHT)#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) +#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
Signature · 1 line
dwmw2
Quoted 8 lines · David Woodhouse
Quoted 2 lines · Jeff Dike
step_sighdlr.c-PTRACE_SINGLESTEPsinto a signal handler, if I'm
reading the code right, fails on i386I haven't looked at this particular test but given the description I think it'll fail on ppc64 too. This ought to fix it for 2.6, along with single-stepping over syscalls and single-stepping over sigreturn (which is a special case).
I fixed it too hard -- we don't need to stop _twice_ at the same instruction on entry to a signal handler; once will suffice...
arch/ppc64/kernel/entry.S renamed from arch/ppc64/kernel/entry.S.sstep +2 -2
@@ -162,7 +162,7 @@ syscall_error_cont: /* check for syscall tracing or audit */ ld r9,TI_FLAGS(r12) - andi. r0,r9,_TIF_SYSCALL_T_OR_A + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) bne- syscall_exit_trace syscall_exit_trace_cont:
@@ -317,7 +317,7 @@ _GLOBAL(ppc64_rt_sigreturn) blt syscall_exit clrrdi r4,r1,THREAD_SHIFT ld r4,TI_FLAGS(r4) - andi. r4,r4,_TIF_SYSCALL_T_OR_A + andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) beq+ 81f bl .do_syscall_trace_leave 81: b .ret_from_except
arch/ppc64/kernel/ptrace.c renamed from arch/ppc64/kernel/ptrace.c.sstep +2 -1
@@ -318,7 +318,8 @@ void do_syscall_trace_leave(void)if (unlikely (current->audit_context))audit_syscall_exit (current,0 );/* FIXME: pass pt_regs */ -if (test_thread_flag (TIF_SYSCALL_TRACE ) +if ((test_thread_flag (TIF_SYSCALL_TRACE ) + ||test_thread_flag (TIF_SINGLESTEP )) && (current->ptrace &PT_PTRACED ))do_syscall_trace (); }
include/asm-ppc64/ptrace-common.h renamed from include/asm-ppc64/ptrace-common.h.sstep +2 -0
@@ -58,6 +58,7 @@ static inline void set_single_step(strucstruct pt_regs *regs = task->thread.regs;if (regs !=NULL ) regs->msr |=MSR_SE ; +set_ti_thread_flag (task->thread_info,TIF_SINGLESTEP ); }static inline void clear_single_step (struct task_struct *task)
@@ -65,6 +66,7 @@ static inline void clear_single_step(strstruct pt_regs *regs = task->thread.regs;if (regs !=NULL ) regs->msr &= ~MSR_SE ; + clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); }#endif /* _PPC64_PTRACE_COMMON_H */
include/asm-ppc64/thread_info.h renamed from include/asm-ppc64/thread_info.h.sstep +2 -0
@@ -97,6 +97,7 @@ static inline struct thread_info *curren#define TIF_RUN_LIGHT 6/* iSeries run light */ #define TIF_ABI_PENDING 7/* 32/64 bit switch needed */ #define TIF_SYSCALL_AUDIT 8/* syscall auditing active */ +#define TIF_SINGLESTEP 9/* singlestepping active */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -108,6 +109,7 @@ static inline struct thread_info *curren#define _TIF_RUN_LIGHT (1<<TIF_RUN_LIGHT)#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) +#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
Signature · 1 line
dwmw2
Quoted 6 lines · Jeff Dike
Quoted 2 lines · [email protected] said:
Could you send one of the test apps? This is something which the arch maintainers might want to look into fixing, thanks.
Quoted 8 lines
Attached...
Included are
breakout.c- UML-specific breakouts, fixed in 2.6 and 2.4 now, but
please don't popularize these :-)
step_sighdlr.c-PTRACE_SINGLESTEPsinto a signal handler, if I'm
reading the code right, fails on i386
I guess, you are notb using i386 2.6.9. On a 2.6.9-vanilla i386 the test doesn't fail! In 2.6.9 some enhancement of singlestepping syscalls and singlestepping signal handlers is included. The test checks, whether UML 2.6.9 is compatible to 2.6.9-i386. With my patchset, it is.
Quoted 3 lines
interrupted_syscall.c- counts signals and system calls during
interrupted system calls, under ptrace and not. Fails on x86 under ptrace.
On my 2.6.7 and 2.6.9 kernels, the test doesn't fail. What kerenel are you using? Could you please send me a listing of the messages from the test?
Quoted 3 lines
kernel_restorer.c- I can't get this to compile because it's too
intimate with the libc headers, expecting to get ak_sigactionfrom them.
On my SuSE 9 system, k_sigaction comes from /usr/include/asm/signal.h. This again comes from glibc-devel-2.3.3-98.28, SuSE supplies. I had to write a "#define __KERNEL__" into the test to have k_sigaction included. If your system lacks a k_sigaction in the includes, please copy a definition from the kernel sources to my test. Yes, that's dirty, but it's a test only! k_sigaction is needed to call sys_sigaction directly, bypassing the lib. This was the only way to test the kernels restorer-stub, since the lib always inserted its own stub, if I used "NULL".
Quoted 5 lines
sigmasking.c- Makes sure that when a signal is (not) delivered to
a bogus stack, that a segfault is delivered then, and not after returning to userspace. This is the test relevant to the patch that Andrew replied to.
Yes. This should be the only test, that shows differences between i386 2.6.9-vanilla and UML 2.6.9 with my patches.
Quoted 2 lines
Jeff
Quoted 2 lines · [email protected] said:
I guess, you are notb using i386 2.6.9. On a 2.6.9-vanilla i386 the test doesn't fail!
Sorry, I should have mentioned that this host was running 2.4 (stock 2.4.26).
Jeff
Quoted 10 lines · Jeff Dike
Quoted 2 lines · [email protected] said:
I guess, you are notb using i386 2.6.9. On a 2.6.9-vanilla i386 the test doesn't fail!
Sorry, I should have mentioned that this host was running 2.4 (stock 2.4.26).
Jeff
Yes. That makes sense. There are substantial changes in syscall restarting between 2.4 and 2.6 (e.g ERESTART_RESTARTBLOCK added). Please run the tests on 2.6.9-i386 to get the correct result: all tests are OK, but sigmasking.
Bodo
Quoted 4 lines · Jeff Dike
sigmasking.c- Makes sure that when a signal is (not) delivered to
a bogus stack, that a segfault is delivered then, and not after returning to userspace. This is the test relevant to the patch that Andrew replied to.
Corresponding patch for ppc64. Are we actually going to fix this for all architectures?
Signature · 1 line
dwmw2
===== arch/ppc64/kernel/signal.c 1.44 vs edited =====
arch/ppc64/kernel/signal.c +10 -7
@@ -387,7 +387,7 @@return 0 ; } -static void setup_rt_frame (int signr,struct k_sigaction *ka,siginfo_t *info, +static int setup_rt_frame (int signr,struct k_sigaction *ka,siginfo_t *info,sigset_t *set,struct pt_regs *regs) {/* Handler is *really* a pointer to the function descriptor for
@@ -452,7 +452,7 @@if (err) goto badframe; -return ; +return 0 ; badframe: #if DEBUG_SIG
@@ -460,17 +460,19 @@ regs, frame, newsp);#endif force_sigsegv (signr, current); +return -1 ; }/* * OK, we're invoking a handler */ -static void handle_signal (unsigned long sig,struct k_sigaction *ka, -siginfo_t *info,sigset_t *oldset,struct pt_regs *regs) +static int handle_signal (unsigned long sig,struct k_sigaction *ka, +siginfo_t *info,sigset_t *oldset,struct pt_regs *regs) {/* Set up Signal Frame */ -setup_rt_frame (sig, ka, info, oldset, regs); +if (setup_rt_frame (sig, ka, info, oldset, regs)) +return 0 ;if (!(ka->sa.sa_flags &SA_NODEFER )) {spin_lock_irq (¤t->sighand->siglock);
@@ -479,6 +481,8 @@recalc_sigpending ();spin_unlock_irq (¤t->sighand->siglock); } + +return 1 ; }static inline void syscall_restart (struct pt_regs *regs,struct k_sigaction *ka)
@@ -538,8 +542,7 @@/* Whee! Actually deliver the signal. */ if (TRAP (regs) ==0x0C00 )syscall_restart (regs, &ka); -handle_signal (signr, &ka, &info, oldset, regs); -return 1 ; +return handle_signal (signr, &ka, &info, oldset, regs); }if (TRAP (regs) ==0x0C00 ) {/* System Call! */
===== arch/ppc64/kernel/signal32.c 1.61 vs edited =====
arch/ppc64/kernel/signal32.c +20 -11
@@ -653,9 +653,9 @@* Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */ -static void handle_rt_signal32 (unsigned long sig,struct k_sigaction *ka, -siginfo_t *info,sigset_t *oldset, -struct pt_regs * regs,unsigned long newsp) +static int handle_rt_signal32 (unsigned long sig,struct k_sigaction *ka, +siginfo_t *info,sigset_t *oldset, +struct pt_regs * regs,unsigned long newsp) {struct rt_sigframe32 __user *rt_sf;struct mcontext32 __user *frame;
@@ -704,14 +704,14 @@ regs->trap =0 ; regs->result =0 ; -return ; +return 1 ; badframe:#if DEBUG_SIG printk ("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n" , regs, frame, newsp);#endif -force_sigsegv (sig, current); +return 0 ; }static long do_setcontext32 (struct ucontext32 __user *ucp,struct pt_regs *regs,int sig)
@@ -822,7 +822,7 @@/* * OK, we're invoking a handler */ -static void handle_signal32 (unsigned long sig,struct k_sigaction *ka, +static int handle_signal32 (unsigned long sig,struct k_sigaction *ka,siginfo_t *info,sigset_t *oldset,struct pt_regs * regs,unsigned long newsp) {
@@ -867,14 +867,14 @@ regs->trap =0 ; regs->result =0 ; -return ; +return 1 ; badframe:#if DEBUG_SIG printk ("badframe in handle_signal, regs=%p frame=%x newsp=%x\n" , regs, frame, *newspp);#endif -force_sigsegv (sig, current); +return 0 ; }/*
@@ -984,11 +984,20 @@/* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags &SA_SIGINFO ) -handle_rt_signal32 (signr, &ka, &info, oldset, regs, newsp); + ret =handle_rt_signal32 (signr, &ka, &info, oldset, regs, newsp);else -handle_signal32 (signr, &ka, &info, oldset, regs, newsp); + ret =handle_signal32 (signr, &ka, &info, oldset, regs, newsp); -if (!(ka.sa.sa_flags &SA_NODEFER )) { +if (!ret) { +/* Setting up the stack frame failed, but if we came here +from sigsuspend we may already have masked signals. +Put back the old sigmask before forcing SEGV. */ +spin_lock_irq (¤t->sighand->siglock); + current->blocked = *oldset; +recalc_sigpending (); +spin_unlock_irq (¤t->sighand->siglock); +force_sigsegv (signr, current); + }else if (!(ka.sa.sa_flags &SA_NODEFER )) {spin_lock_irq (¤t->sighand->siglock);sigorsets (¤t->blocked, ¤t->blocked, &ka.sa.sa_mask);
Quoted 6 lines · David Woodhouse
Quoted 4 lines · Jeff Dike
sigmasking.c- Makes sure that when a signal is (not) delivered to
a bogus stack, that a segfault is delivered then, and not after returning to userspace. This is the test relevant to the patch that Andrew replied to.
I don't know much about ppc64 and also don't have a machine to test. So, I'm commenting the code only. If I've missed something, sorry for that.
The changes we did in UML, fiy two major issues:
1) they correct the sigmask after a segfault that happened in signal-delivery
2) they immediately deliver that SIGSEGV, before returning to user.
AFAICS, the patch seems to cover the first, but not the second. If a SIGSEGV is forced since the stackframe/sigcontext for a signal-handler could not be created, this SIGSEGV is queued only. To deliver it, do_signal() must be called again, which normally won't happen (with the exception of sys_sigretrun/sys_rt_sigreturn). Thus, SIGSEGV stays in the queue until the next interrupt or syscall happens. IMHO this behavior is bad.
So, in UML we changed (kern_)do_signal, to loop over get_signal_to_deliver and handle_signal, until a signal is delivered correctly or the task exits.
Bodo
Quoted 155 lines
Corresponding patch for ppc64. Are we actually going to fix this for all architectures?
------------------------------------------------------------------------
=====
arch/ppc64/kernel/signal.c1.44 vs edited =====arch/ppc64/kernel/signal.c +10
-7@@ -387,7 +387,7 @@return 0 ; } -static void setup_rt_frame (int signr,struct k_sigaction *ka,siginfo_t *info, +static int setup_rt_frame (int signr,struct k_sigaction *ka,siginfo_t *info,sigset_t *set,struct pt_regs *regs) {/* Handler is *really* a pointer to the function descriptor for @@ -452,7 +452,7 @@if (err) goto badframe; -return ; +return 0 ; badframe: #if DEBUG_SIG@@ -460,17 +460,19 @@ regs, frame, newsp);#endif force_sigsegv (signr, current); +return -1 ; }/* * OK, we're invoking a handler */ -static void handle_signal (unsigned long sig,struct k_sigaction *ka, -siginfo_t *info,sigset_t *oldset,struct pt_regs *regs) +static int handle_signal (unsigned long sig,struct k_sigaction *ka, +siginfo_t *info,sigset_t *oldset,struct pt_regs *regs) {/* Set up Signal Frame */ -setup_rt_frame (sig, ka, info, oldset, regs); +if (setup_rt_frame (sig, ka, info, oldset, regs)) +return 0 ;if (!(ka->sa.sa_flags &SA_NODEFER )) {spin_lock_irq (¤t->sighand->siglock);@@ -479,6 +481,8 @@recalc_sigpending ();spin_unlock_irq (¤t->sighand->siglock); } + +return 1 ; }static inline void syscall_restart (struct pt_regs *regs,struct k_sigaction *ka)@@ -538,8 +542,7 @@/* Whee! Actually deliver the signal. */ if (TRAP (regs) ==0x0C00 )syscall_restart (regs, &ka); -handle_signal (signr, &ka, &info, oldset, regs); -return 1 ; +return handle_signal (signr, &ka, &info, oldset, regs); }if (TRAP (regs) ==0x0C00 ) {/* System Call! */ =====
arch/ppc64/kernel/signal32.c1.61 vs edited =====arch/ppc64/kernel/signal32.c +20
-11@@ -653,9 +653,9 @@* Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */ -static void handle_rt_signal32 (unsigned long sig,struct k_sigaction *ka, -siginfo_t *info,sigset_t *oldset, -struct pt_regs * regs,unsigned long newsp) +static int handle_rt_signal32 (unsigned long sig,struct k_sigaction *ka, +siginfo_t *info,sigset_t *oldset, +struct pt_regs * regs,unsigned long newsp) {struct rt_sigframe32 __user *rt_sf;struct mcontext32 __user *frame;@@ -704,14 +704,14 @@ regs->trap =0 ; regs->result =0 ; -return ; +return 1 ; badframe:#if DEBUG_SIG printk ("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n" , regs, frame, newsp);#endif -force_sigsegv (sig, current); +return 0 ; }static long do_setcontext32 (struct ucontext32 __user *ucp,struct pt_regs *regs,int sig)@@ -822,7 +822,7 @@/* * OK, we're invoking a handler */ -static void handle_signal32 (unsigned long sig,struct k_sigaction *ka, +static int handle_signal32 (unsigned long sig,struct k_sigaction *ka,siginfo_t *info,sigset_t *oldset,struct pt_regs * regs,unsigned long newsp) {@@ -867,14 +867,14 @@ regs->trap =0 ; regs->result =0 ; -return ; +return 1 ; badframe:#if DEBUG_SIG printk ("badframe in handle_signal, regs=%p frame=%x newsp=%x\n" , regs, frame, *newspp);#endif -force_sigsegv (sig, current); +return 0 ; }/* @@ -984,11 +984,20 @@/* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags &SA_SIGINFO ) -handle_rt_signal32 (signr, &ka, &info, oldset, regs, newsp); + ret =handle_rt_signal32 (signr, &ka, &info, oldset, regs, newsp);else -handle_signal32 (signr, &ka, &info, oldset, regs, newsp); + ret =handle_signal32 (signr, &ka, &info, oldset, regs, newsp); -if (!(ka.sa.sa_flags &SA_NODEFER )) { +if (!ret) { +/* Setting up the stack frame failed, but if we came here +from sigsuspend we may already have masked signals. +Put back the old sigmask before forcing SEGV. */ +spin_lock_irq (¤t->sighand->siglock); + current->blocked = *oldset; +recalc_sigpending (); +spin_unlock_irq (¤t->sighand->siglock); +force_sigsegv (signr, current); + }else if (!(ka.sa.sa_flags &SA_NODEFER )) {spin_lock_irq (¤t->sighand->siglock);sigorsets (¤t->blocked, ¤t->blocked, &ka.sa.sa_mask);
Quoted 4 lines · Bodo Stroesser
If a SIGSEGV is forced since the stackframe/sigcontext for a signal-handler could not be created, this SIGSEGV is queued only. To deliver it,
do_signal()must be called again, which normally won't happen (with the exception of sys_sigretrun/sys_rt_sigreturn). Thus, SIGSEGV stays in the queue until the
We got this right on ppc/ppc64, I believe. After calling do_signal, we loop around again (in the exception exit path in entry.S) and check the signal pending and reschedule bits again (in the thread_info flags). We only exit to usermode when they are both zero.
Paul.
Quoted 9 lines · Paul Mackerras
Quoted 4 lines · Bodo Stroesser
If a SIGSEGV is forced since the stackframe/sigcontext for a signal-handler could not be created, this SIGSEGV is queued only. To deliver it,
do_signal()must be called again, which normally won't happen (with the exception of sys_sigretrun/sys_rt_sigreturn). Thus, SIGSEGV stays in the queue until the
Quoted 6 lines
We got this right on ppc/ppc64, I believe. After calling
do_signal, we loop around again (in the exception exit path inentry.S) and check the signal pending and reschedule bits again (in thethread_infoflags). We only exit to usermode when they are both zero.Paul.
Aha! Sorry, didn't recognize that loop.
Bodo