Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull signal fixes from Eric Biederman: "This contains four small fixes for signal handling. A missing range check, a regression fix, prioritizing signals we have already started a signal group exit for, and better detection of synchronous signals. The confused decision of which signals to handle failed spectacularly when a timer was pointed at SIGBUS and the stack overflowed. Resulting in an unkillable process in an infinite loop instead of a SIGSEGV and core dump" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: signal: Better detection of synchronous signals signal: Always notice exiting tasks signal: Always attempt to allocate siginfo for SIGSTOP signal: Make siginmask safe when passed a signal of 0
This commit is contained in:
commit
6b2912cedc
|
@ -392,7 +392,7 @@ extern bool unhandled_signal(struct task_struct *tsk, int sig);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define siginmask(sig, mask) \
|
#define siginmask(sig, mask) \
|
||||||
((sig) < SIGRTMIN && (rt_sigmask(sig) & (mask)))
|
((sig) > 0 && (sig) < SIGRTMIN && (rt_sigmask(sig) & (mask)))
|
||||||
|
|
||||||
#define SIG_KERNEL_ONLY_MASK (\
|
#define SIG_KERNEL_ONLY_MASK (\
|
||||||
rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP))
|
rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP))
|
||||||
|
|
|
@ -688,6 +688,48 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *in
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dequeue_signal);
|
EXPORT_SYMBOL_GPL(dequeue_signal);
|
||||||
|
|
||||||
|
static int dequeue_synchronous_signal(kernel_siginfo_t *info)
|
||||||
|
{
|
||||||
|
struct task_struct *tsk = current;
|
||||||
|
struct sigpending *pending = &tsk->pending;
|
||||||
|
struct sigqueue *q, *sync = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Might a synchronous signal be in the queue?
|
||||||
|
*/
|
||||||
|
if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the first synchronous signal in the queue.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(q, &pending->list, list) {
|
||||||
|
/* Synchronous signals have a postive si_code */
|
||||||
|
if ((q->info.si_code > SI_USER) &&
|
||||||
|
(sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
|
||||||
|
sync = q;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
next:
|
||||||
|
/*
|
||||||
|
* Check if there is another siginfo for the same signal.
|
||||||
|
*/
|
||||||
|
list_for_each_entry_continue(q, &pending->list, list) {
|
||||||
|
if (q->info.si_signo == sync->info.si_signo)
|
||||||
|
goto still_pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigdelset(&pending->signal, sync->info.si_signo);
|
||||||
|
recalc_sigpending();
|
||||||
|
still_pending:
|
||||||
|
list_del_init(&sync->list);
|
||||||
|
copy_siginfo(info, &sync->info);
|
||||||
|
__sigqueue_free(sync);
|
||||||
|
return info->si_signo;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell a process that it has a new active signal..
|
* Tell a process that it has a new active signal..
|
||||||
*
|
*
|
||||||
|
@ -1057,10 +1099,9 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc
|
||||||
|
|
||||||
result = TRACE_SIGNAL_DELIVERED;
|
result = TRACE_SIGNAL_DELIVERED;
|
||||||
/*
|
/*
|
||||||
* Skip useless siginfo allocation for SIGKILL SIGSTOP,
|
* Skip useless siginfo allocation for SIGKILL and kernel threads.
|
||||||
* and kernel threads.
|
|
||||||
*/
|
*/
|
||||||
if (sig_kernel_only(sig) || (t->flags & PF_KTHREAD))
|
if ((sig == SIGKILL) || (t->flags & PF_KTHREAD))
|
||||||
goto out_set;
|
goto out_set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2394,6 +2435,11 @@ relock:
|
||||||
goto relock;
|
goto relock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Has this task already been marked for death? */
|
||||||
|
ksig->info.si_signo = signr = SIGKILL;
|
||||||
|
if (signal_group_exit(signal))
|
||||||
|
goto fatal;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct k_sigaction *ka;
|
struct k_sigaction *ka;
|
||||||
|
|
||||||
|
@ -2407,7 +2453,15 @@ relock:
|
||||||
goto relock;
|
goto relock;
|
||||||
}
|
}
|
||||||
|
|
||||||
signr = dequeue_signal(current, ¤t->blocked, &ksig->info);
|
/*
|
||||||
|
* Signals generated by the execution of an instruction
|
||||||
|
* need to be delivered before any other pending signals
|
||||||
|
* so that the instruction pointer in the signal stack
|
||||||
|
* frame points to the faulting instruction.
|
||||||
|
*/
|
||||||
|
signr = dequeue_synchronous_signal(&ksig->info);
|
||||||
|
if (!signr)
|
||||||
|
signr = dequeue_signal(current, ¤t->blocked, &ksig->info);
|
||||||
|
|
||||||
if (!signr)
|
if (!signr)
|
||||||
break; /* will return 0 */
|
break; /* will return 0 */
|
||||||
|
@ -2489,6 +2543,7 @@ relock:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fatal:
|
||||||
spin_unlock_irq(&sighand->siglock);
|
spin_unlock_irq(&sighand->siglock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue