Commit c8e85b4f4b9ee23bf0e79bdeb3da274a0f9c663f

Authored by Oleg Nesterov
Committed by Linus Torvalds
1 parent 84a881657d

posix timers: sigqueue_free: don't free sigqueue if it is queued

Currently sigqueue_free() removes sigqueue from list, but doesn't cancel the
pending signal. This is not consistent, the task should either receive the
"full" signal along with siginfo_t, or it shouldn't receive the signal at all.

Change sigqueue_free() to clear SIGQUEUE_PREALLOC but leave sigqueue on list
if it is queued.

This is a user-visible change. If the signal is blocked, it stays queued
after sys_timer_delete() until unblocked with the "stale" si_code/si_value,
and of course it is still counted wrt RLIMIT_SIGPENDING which also limits
the number of posix timers.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Austin Clements <amdragon+kernelbugzilla@mit.edu>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 10 additions and 6 deletions Side-by-side Diff

... ... @@ -1240,18 +1240,22 @@
1240 1240  
1241 1241 BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
1242 1242 /*
1243   - * If the signal is still pending remove it from the
1244   - * pending queue. We must hold ->siglock while testing
1245   - * q->list to serialize with collect_signal() or with
  1243 + * We must hold ->siglock while testing q->list
  1244 + * to serialize with collect_signal() or with
1246 1245 * __exit_signal()->flush_sigqueue().
1247 1246 */
1248 1247 spin_lock_irqsave(lock, flags);
  1248 + q->flags &= ~SIGQUEUE_PREALLOC;
  1249 + /*
  1250 + * If it is queued it will be freed when dequeued,
  1251 + * like the "regular" sigqueue.
  1252 + */
1249 1253 if (!list_empty(&q->list))
1250   - list_del_init(&q->list);
  1254 + q = NULL;
1251 1255 spin_unlock_irqrestore(lock, flags);
1252 1256  
1253   - q->flags &= ~SIGQUEUE_PREALLOC;
1254   - __sigqueue_free(q);
  1257 + if (q)
  1258 + __sigqueue_free(q);
1255 1259 }
1256 1260  
1257 1261 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)