Skip to content

Commit

Permalink
posix timers: discard SI_TIMER signals on exec
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Oleg Nesterov authored and torvalds committed May 26, 2008
1 parent c8e85b4 commit cbaffba
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 0 deletions.
1 change: 1 addition & 0 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ static int de_thread(struct task_struct *tsk)

no_thread_group:
exit_itimers(sig);
flush_itimer_signals();
if (leader)
release_task(leader);

Expand Down
2 changes: 2 additions & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1848,7 +1848,9 @@ extern void exit_thread(void);
extern void exit_files(struct task_struct *);
extern void __cleanup_signal(struct signal_struct *);
extern void __cleanup_sighand(struct sighand_struct *);

extern void exit_itimers(struct signal_struct *);
extern void flush_itimer_signals(void);

extern NORET_TYPE void do_group_exit(int);

Expand Down
34 changes: 34 additions & 0 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,40 @@ void flush_signals(struct task_struct *t)
spin_unlock_irqrestore(&t->sighand->siglock, flags);
}

static void __flush_itimer_signals(struct sigpending *pending)
{
sigset_t signal, retain;
struct sigqueue *q, *n;

signal = pending->signal;
sigemptyset(&retain);

list_for_each_entry_safe(q, n, &pending->list, list) {
int sig = q->info.si_signo;

if (likely(q->info.si_code != SI_TIMER)) {
sigaddset(&retain, sig);
} else {
sigdelset(&signal, sig);
list_del_init(&q->list);
__sigqueue_free(q);
}
}

sigorsets(&pending->signal, &signal, &retain);
}

void flush_itimer_signals(void)
{
struct task_struct *tsk = current;
unsigned long flags;

spin_lock_irqsave(&tsk->sighand->siglock, flags);
__flush_itimer_signals(&tsk->pending);
__flush_itimer_signals(&tsk->signal->shared_pending);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
}

void ignore_signals(struct task_struct *t)
{
int i;
Expand Down

0 comments on commit cbaffba

Please sign in to comment.