Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull third pile of signal handling patches from Al Viro: "This time it's mostly helpers and conversions to them; there's a lot of stuff remaining in the tree, but that'll either go in -rc2 (isolated bug fixes, ideally via arch maintainers' trees) or will sit there until the next cycle." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: x86: get rid of calling do_notify_resume() when returning to kernel mode blackfin: check __get_user() return value whack-a-mole with TIF_FREEZE FRV: Optimise the system call exit path in entry.S [ver #2] FRV: Shrink TIF_WORK_MASK [ver #2] FRV: Prevent syscall exit tracing and notify_resume at end of kernel exceptions new helper: signal_delivered() powerpc: get rid of restore_sigmask() most of set_current_blocked() callers want SIGKILL/SIGSTOP removed from set set_restore_sigmask() is never called without SIGPENDING (and never should be) TIF_RESTORE_SIGMASK can be set only when TIF_SIGPENDING is set don't call try_to_freeze() from do_signal() pull clearing RESTORE_SIGMASK into block_sigmask() sh64: failure to build sigframe != signal without handler openrisc: tracehook_signal_handler() is supposed to be called on success new helper: sigmask_to_save() new helper: restore_saved_sigmask() new helpers: {clear,test,test_and_clear}_restore_sigmask() HAVE_RESTORE_SIGMASK is defined on all architectures now
This commit is contained in:
@@ -131,8 +131,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
|
||||
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
|
||||
|
||||
#define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \
|
||||
_TIF_SIGPENDING | \
|
||||
_TIF_RESTORE_SIGMASK)
|
||||
_TIF_SIGPENDING)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
@@ -238,7 +238,23 @@ static inline void set_restore_sigmask(void)
|
||||
{
|
||||
struct thread_info *ti = current_thread_info();
|
||||
ti->status |= TS_RESTORE_SIGMASK;
|
||||
set_bit(TIF_SIGPENDING, &ti->flags);
|
||||
WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags));
|
||||
}
|
||||
static inline void clear_restore_sigmask(void)
|
||||
{
|
||||
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
|
||||
}
|
||||
static inline bool test_restore_sigmask(void)
|
||||
{
|
||||
return current_thread_info()->status & TS_RESTORE_SIGMASK;
|
||||
}
|
||||
static inline bool test_and_clear_restore_sigmask(void)
|
||||
{
|
||||
struct thread_info *ti = current_thread_info();
|
||||
if (!(ti->status & TS_RESTORE_SIGMASK))
|
||||
return false;
|
||||
ti->status &= ~TS_RESTORE_SIGMASK;
|
||||
return true;
|
||||
}
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
@@ -32,8 +32,6 @@
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
/* This magic should be in g_upper[0] for all upper parts
|
||||
* to be valid.
|
||||
*/
|
||||
@@ -274,7 +272,6 @@ void do_sigreturn32(struct pt_regs *regs)
|
||||
case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
|
||||
case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
|
||||
}
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
return;
|
||||
|
||||
@@ -376,7 +373,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||
case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32);
|
||||
case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
|
||||
}
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
return;
|
||||
segv:
|
||||
@@ -775,7 +771,7 @@ sigsegv:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
|
||||
static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
|
||||
siginfo_t *info,
|
||||
sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
@@ -787,12 +783,9 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
|
||||
err = setup_frame32(ka, regs, signr, oldset);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return;
|
||||
|
||||
block_sigmask(ka, signr);
|
||||
tracehook_signal_handler(signr, info, ka, regs, 0);
|
||||
|
||||
return 0;
|
||||
signal_delivered(signr, info, ka, regs, 0);
|
||||
}
|
||||
|
||||
static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
|
||||
@@ -841,14 +834,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs)
|
||||
if (signr > 0) {
|
||||
if (restart_syscall)
|
||||
syscall_restart32(orig_i0, regs, &ka.sa);
|
||||
if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) {
|
||||
/* A signal was successfully delivered; the saved
|
||||
* sigmask will have been stored in the signal frame,
|
||||
* and will be restored by sigreturn, so we can simply
|
||||
* clear the TS_RESTORE_SIGMASK flag.
|
||||
*/
|
||||
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
|
||||
}
|
||||
handle_signal32(signr, &ka, &info, oldset, regs);
|
||||
return;
|
||||
}
|
||||
if (restart_syscall &&
|
||||
@@ -872,10 +858,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs)
|
||||
/* If there's no signal to deliver, we just put the saved sigmask
|
||||
* back
|
||||
*/
|
||||
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
|
||||
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
|
||||
set_current_blocked(¤t->saved_sigmask);
|
||||
}
|
||||
restore_saved_sigmask();
|
||||
}
|
||||
|
||||
struct sigstack32 {
|
||||
|
@@ -29,8 +29,6 @@
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
|
||||
void *fpqueue, unsigned long *fpqdepth);
|
||||
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
|
||||
@@ -130,7 +128,6 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||
if (err)
|
||||
goto segv_and_exit;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
return;
|
||||
|
||||
@@ -197,7 +194,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||
goto segv;
|
||||
}
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
return;
|
||||
segv:
|
||||
@@ -449,10 +445,11 @@ sigsegv:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static inline int
|
||||
static inline void
|
||||
handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
|
||||
siginfo_t *info, struct pt_regs *regs)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
int err;
|
||||
|
||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||
@@ -461,12 +458,9 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||
err = setup_frame(ka, regs, signr, oldset);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return;
|
||||
|
||||
block_sigmask(ka, signr);
|
||||
tracehook_signal_handler(signr, info, ka, regs, 0);
|
||||
|
||||
return 0;
|
||||
signal_delivered(signr, info, ka, regs, 0);
|
||||
}
|
||||
|
||||
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
|
||||
@@ -498,7 +492,6 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
{
|
||||
struct k_sigaction ka;
|
||||
int restart_syscall;
|
||||
sigset_t *oldset;
|
||||
siginfo_t info;
|
||||
int signr;
|
||||
|
||||
@@ -523,11 +516,6 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
|
||||
regs->u_regs[UREG_G6] = orig_i0;
|
||||
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
||||
oldset = ¤t->saved_sigmask;
|
||||
else
|
||||
oldset = ¤t->blocked;
|
||||
|
||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
|
||||
/* If the debugger messes with the program counter, it clears
|
||||
@@ -544,15 +532,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
if (signr > 0) {
|
||||
if (restart_syscall)
|
||||
syscall_restart(orig_i0, regs, &ka.sa);
|
||||
if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
|
||||
/* a signal was successfully delivered; the saved
|
||||
* sigmask will have been stored in the signal frame,
|
||||
* and will be restored by sigreturn, so we can simply
|
||||
* clear the TIF_RESTORE_SIGMASK flag.
|
||||
*/
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
}
|
||||
handle_signal(signr, &ka, &info, regs);
|
||||
return;
|
||||
}
|
||||
if (restart_syscall &&
|
||||
@@ -576,16 +556,13 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
/* if there's no signal to deliver, we just put the saved sigmask
|
||||
* back
|
||||
*/
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
set_current_blocked(¤t->saved_sigmask);
|
||||
}
|
||||
restore_saved_sigmask();
|
||||
}
|
||||
|
||||
void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
|
||||
unsigned long thread_info_flags)
|
||||
{
|
||||
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
||||
if (thread_info_flags & _TIF_SIGPENDING)
|
||||
do_signal(regs, orig_i0);
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
|
@@ -38,8 +38,6 @@
|
||||
#include "systbls.h"
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
/* {set, get}context() needed for 64-bit SparcLinux userland. */
|
||||
asmlinkage void sparc64_set_context(struct pt_regs *regs)
|
||||
{
|
||||
@@ -71,7 +69,6 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
|
||||
if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t)))
|
||||
goto do_sigsegv;
|
||||
}
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
}
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
@@ -315,7 +312,6 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
||||
/* Prevent syscall restart. */
|
||||
pt_regs_clear_syscall(regs);
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
set_current_blocked(&set);
|
||||
return;
|
||||
segv:
|
||||
@@ -466,7 +462,7 @@ sigsegv:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||
static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||
siginfo_t *info,
|
||||
sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
@@ -475,12 +471,9 @@ static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||
err = setup_rt_frame(ka, regs, signr, oldset,
|
||||
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
|
||||
if (err)
|
||||
return err;
|
||||
return;
|
||||
|
||||
block_sigmask(ka, signr);
|
||||
tracehook_signal_handler(signr, info, ka, regs, 0);
|
||||
|
||||
return 0;
|
||||
signal_delivered(signr, info, ka, regs, 0);
|
||||
}
|
||||
|
||||
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
|
||||
@@ -512,7 +505,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
{
|
||||
struct k_sigaction ka;
|
||||
int restart_syscall;
|
||||
sigset_t *oldset;
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
siginfo_t info;
|
||||
int signr;
|
||||
|
||||
@@ -538,11 +531,6 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
|
||||
regs->u_regs[UREG_G6] = orig_i0;
|
||||
|
||||
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
|
||||
oldset = ¤t->saved_sigmask;
|
||||
else
|
||||
oldset = ¤t->blocked;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
extern void do_signal32(sigset_t *, struct pt_regs *);
|
||||
@@ -563,14 +551,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
if (signr > 0) {
|
||||
if (restart_syscall)
|
||||
syscall_restart(orig_i0, regs, &ka.sa);
|
||||
if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
|
||||
/* A signal was successfully delivered; the saved
|
||||
* sigmask will have been stored in the signal frame,
|
||||
* and will be restored by sigreturn, so we can simply
|
||||
* clear the TS_RESTORE_SIGMASK flag.
|
||||
*/
|
||||
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
|
||||
}
|
||||
handle_signal(signr, &ka, &info, oldset, regs);
|
||||
return;
|
||||
}
|
||||
if (restart_syscall &&
|
||||
@@ -594,10 +575,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||
/* If there's no signal to deliver, we just put the saved sigmask
|
||||
* back
|
||||
*/
|
||||
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
|
||||
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
|
||||
set_current_blocked(¤t->saved_sigmask);
|
||||
}
|
||||
restore_saved_sigmask();
|
||||
}
|
||||
|
||||
void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags)
|
||||
|
Reference in New Issue
Block a user