Commit f65013d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull timer fix from Eric Biederman:
 "This fixes an issue of confusing injected signals with the signals
  from posix timers that has existed since posix timers have been in the
  kernel.

  This patch is slightly simpler than my earlier version of this patch
  as I discovered in testing that I had misspelled "#ifdef
  CONFIG_POSIX_TIMERS". So I deleted that unnecessary test and made
  setting of resched_timer uncondtional.

  I have tested this and verified that without this patch there is a
  nasty hang that is easy to trigger, and with this patch everything
  works properly"

Thomas Gleixner dixit:
 "It fixes the problem at hand and covers the ptrace case as well, which
  I missed.

  Reviewed-and-tested-by: Thomas Gleixner <tglx@linutronix.de>"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  signal: Only reschedule timers on signals timers have sent
parents 94a6df25 57db7e4a
...@@ -510,7 +510,8 @@ int unhandled_signal(struct task_struct *tsk, int sig) ...@@ -510,7 +510,8 @@ int unhandled_signal(struct task_struct *tsk, int sig)
return !tsk->ptrace; return !tsk->ptrace;
} }
static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
bool *resched_timer)
{ {
struct sigqueue *q, *first = NULL; struct sigqueue *q, *first = NULL;
...@@ -532,6 +533,12 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) ...@@ -532,6 +533,12 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
still_pending: still_pending:
list_del_init(&first->list); list_del_init(&first->list);
copy_siginfo(info, &first->info); copy_siginfo(info, &first->info);
*resched_timer =
(first->flags & SIGQUEUE_PREALLOC) &&
(info->si_code == SI_TIMER) &&
(info->si_sys_private);
__sigqueue_free(first); __sigqueue_free(first);
} else { } else {
/* /*
...@@ -548,12 +555,12 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) ...@@ -548,12 +555,12 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
} }
static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
siginfo_t *info) siginfo_t *info, bool *resched_timer)
{ {
int sig = next_signal(pending, mask); int sig = next_signal(pending, mask);
if (sig) if (sig)
collect_signal(sig, pending, info); collect_signal(sig, pending, info, resched_timer);
return sig; return sig;
} }
...@@ -565,15 +572,16 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, ...@@ -565,15 +572,16 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
*/ */
int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
{ {
bool resched_timer = false;
int signr; int signr;
/* We only dequeue private signals from ourselves, we don't let /* We only dequeue private signals from ourselves, we don't let
* signalfd steal them * signalfd steal them
*/ */
signr = __dequeue_signal(&tsk->pending, mask, info); signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
if (!signr) { if (!signr) {
signr = __dequeue_signal(&tsk->signal->shared_pending, signr = __dequeue_signal(&tsk->signal->shared_pending,
mask, info); mask, info, &resched_timer);
#ifdef CONFIG_POSIX_TIMERS #ifdef CONFIG_POSIX_TIMERS
/* /*
* itimer signal ? * itimer signal ?
...@@ -621,7 +629,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -621,7 +629,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
current->jobctl |= JOBCTL_STOP_DEQUEUED; current->jobctl |= JOBCTL_STOP_DEQUEUED;
} }
#ifdef CONFIG_POSIX_TIMERS #ifdef CONFIG_POSIX_TIMERS
if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { if (resched_timer) {
/* /*
* Release the siglock to ensure proper locking order * Release the siglock to ensure proper locking order
* of timer locks outside of siglocks. Note, we leave * of timer locks outside of siglocks. Note, we leave
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment