Skip to content

Commit

Permalink
change kernel threads to ignore signals instead of blocking them
Browse files Browse the repository at this point in the history
Currently kernel threads use sigprocmask(SIG_BLOCK) to protect against
signals.  This doesn't prevent the signal delivery, this only blocks
signal_wake_up().  Every "killall -33 kthreadd" means a "struct siginfo"
leak.

Change kthreadd_setup() to set all handlers to SIG_IGN instead of blocking
them (make a new helper ignore_signals() for that).  If the kernel thread
needs some signal, it should use allow_signal() anyway, and in that case it
should not use CLONE_SIGHAND.

Note that we can't change daemonize() (should die!) in the same way,
because it can be used along with CLONE_SIGHAND.  This means that
allow_signal() still should unblock the signal to work correctly with
daemonize()ed threads.

However, disallow_signal() doesn't block the signal any longer but ignores
it.

NOTE: with or without this patch the kernel threads are not protected from
handle_stop_signal(), this seems harmless, but not good.

Signed-off-by: Oleg Nesterov <[email protected]>
Acked-by: "Eric W. Biederman" <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Oleg Nesterov authored and Linus Torvalds committed May 9, 2007
1 parent 5de18d1 commit 10ab825
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 15 deletions.
1 change: 1 addition & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,7 @@ extern int in_egroup_p(gid_t);

extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);

Expand Down
2 changes: 1 addition & 1 deletion kernel/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ int disallow_signal(int sig)
return -EINVAL;

spin_lock_irq(&current->sighand->siglock);
sigaddset(&current->blocked, sig);
current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
return 0;
Expand Down
17 changes: 3 additions & 14 deletions kernel/kthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,24 +215,13 @@ EXPORT_SYMBOL(kthread_stop);
static __init void kthreadd_setup(void)
{
struct task_struct *tsk = current;
struct k_sigaction sa;
sigset_t blocked;

set_task_comm(tsk, "kthreadd");

/* Block and flush all signals */
sigfillset(&blocked);
sigprocmask(SIG_BLOCK, &blocked, NULL);
flush_signals(tsk);
ignore_signals(tsk);

/* SIG_IGN makes children autoreap: see do_notify_parent(). */
sa.sa.sa_handler = SIG_IGN;
sa.sa.sa_flags = 0;
siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);

set_user_nice(current, -5);
set_cpus_allowed(current, CPU_MASK_ALL);
set_user_nice(tsk, -5);
set_cpus_allowed(tsk, CPU_MASK_ALL);
}

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

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

for (i = 0; i < _NSIG; ++i)
t->sighand->action[i].sa.sa_handler = SIG_IGN;

flush_signals(t);
}

/*
* Flush all handlers for a task.
*/
Expand Down

0 comments on commit 10ab825

Please sign in to comment.