aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-05-26 12:55:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-26 13:37:07 -0400
commitcbaffba12ce08beb3e80bfda148ee0fa14aac188 (patch)
treeb35f29814b46593d864e8c8921e9eccac5a5a173
parentc8e85b4f4b9ee23bf0e79bdeb3da274a0f9c663f (diff)
posix timers: discard SI_TIMER signals on exec
Based on Roland's patch. This approach was suggested by Austin Clements from the very beginning, and then by Linus. As Austin pointed out, the execing task can be killed by SI_TIMER signal because exec flushes the signal handlers, but doesn't discard the pending signals generated by posix timers. Perhaps not a bug, but people find this surprising. See http://bugzilla.kernel.org/show_bug.cgi?id=10460 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>
-rw-r--r--fs/exec.c1
-rw-r--r--include/linux/sched.h2
-rw-r--r--kernel/signal.c34
3 files changed, 37 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 3c2ba7ce11d4..9448f1b50b4a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -860,6 +860,7 @@ static int de_thread(struct task_struct *tsk)
860 860
861no_thread_group: 861no_thread_group:
862 exit_itimers(sig); 862 exit_itimers(sig);
863 flush_itimer_signals();
863 if (leader) 864 if (leader)
864 release_task(leader); 865 release_task(leader);
865 866
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5395a6176f4b..3e05e5474749 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1848,7 +1848,9 @@ extern void exit_thread(void);
1848extern void exit_files(struct task_struct *); 1848extern void exit_files(struct task_struct *);
1849extern void __cleanup_signal(struct signal_struct *); 1849extern void __cleanup_signal(struct signal_struct *);
1850extern void __cleanup_sighand(struct sighand_struct *); 1850extern void __cleanup_sighand(struct sighand_struct *);
1851
1851extern void exit_itimers(struct signal_struct *); 1852extern void exit_itimers(struct signal_struct *);
1853extern void flush_itimer_signals(void);
1852 1854
1853extern NORET_TYPE void do_group_exit(int); 1855extern NORET_TYPE void do_group_exit(int);
1854 1856
diff --git a/kernel/signal.c b/kernel/signal.c
index 2955f6c4f36e..6c0958e52ea7 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -231,6 +231,40 @@ void flush_signals(struct task_struct *t)
231 spin_unlock_irqrestore(&t->sighand->siglock, flags); 231 spin_unlock_irqrestore(&t->sighand->siglock, flags);
232} 232}
233 233
234static void __flush_itimer_signals(struct sigpending *pending)
235{
236 sigset_t signal, retain;
237 struct sigqueue *q, *n;
238
239 signal = pending->signal;
240 sigemptyset(&retain);
241
242 list_for_each_entry_safe(q, n, &pending->list, list) {
243 int sig = q->info.si_signo;
244
245 if (likely(q->info.si_code != SI_TIMER)) {
246 sigaddset(&retain, sig);
247 } else {
248 sigdelset(&signal, sig);
249 list_del_init(&q->list);
250 __sigqueue_free(q);
251 }
252 }
253
254 sigorsets(&pending->signal, &signal, &retain);
255}
256
257void flush_itimer_signals(void)
258{
259 struct task_struct *tsk = current;
260 unsigned long flags;
261
262 spin_lock_irqsave(&tsk->sighand->siglock, flags);
263 __flush_itimer_signals(&tsk->pending);
264 __flush_itimer_signals(&tsk->signal->shared_pending);
265 spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
266}
267
234void ignore_signals(struct task_struct *t) 268void ignore_signals(struct task_struct *t)
235{ 269{
236 int i; 270 int i;