Commit 10ab825bdef8df510f99c703a5a2d9b13a4e31a5

Authored by Oleg Nesterov
Committed by Linus Torvalds
1 parent 5de18d1697

change kernel threads to ignore signals instead of blocking them

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 <oleg@tv-sign.ru>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 15 additions and 15 deletions Side-by-side Diff

include/linux/sched.h
... ... @@ -1317,6 +1317,7 @@
1317 1317  
1318 1318 extern void proc_caches_init(void);
1319 1319 extern void flush_signals(struct task_struct *);
  1320 +extern void ignore_signals(struct task_struct *);
1320 1321 extern void flush_signal_handlers(struct task_struct *, int force_default);
1321 1322 extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
1322 1323  
... ... @@ -347,7 +347,7 @@
347 347 return -EINVAL;
348 348  
349 349 spin_lock_irq(&current->sighand->siglock);
350   - sigaddset(&current->blocked, sig);
  350 + current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;
351 351 recalc_sigpending();
352 352 spin_unlock_irq(&current->sighand->siglock);
353 353 return 0;
... ... @@ -215,24 +215,13 @@
215 215 static __init void kthreadd_setup(void)
216 216 {
217 217 struct task_struct *tsk = current;
218   - struct k_sigaction sa;
219   - sigset_t blocked;
220 218  
221 219 set_task_comm(tsk, "kthreadd");
222 220  
223   - /* Block and flush all signals */
224   - sigfillset(&blocked);
225   - sigprocmask(SIG_BLOCK, &blocked, NULL);
226   - flush_signals(tsk);
  221 + ignore_signals(tsk);
227 222  
228   - /* SIG_IGN makes children autoreap: see do_notify_parent(). */
229   - sa.sa.sa_handler = SIG_IGN;
230   - sa.sa.sa_flags = 0;
231   - siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
232   - do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
233   -
234   - set_user_nice(current, -5);
235   - set_cpus_allowed(current, CPU_MASK_ALL);
  223 + set_user_nice(tsk, -5);
  224 + set_cpus_allowed(tsk, CPU_MASK_ALL);
236 225 }
237 226  
238 227 int kthreadd(void *unused)
... ... @@ -209,6 +209,16 @@
209 209 spin_unlock_irqrestore(&t->sighand->siglock, flags);
210 210 }
211 211  
  212 +void ignore_signals(struct task_struct *t)
  213 +{
  214 + int i;
  215 +
  216 + for (i = 0; i < _NSIG; ++i)
  217 + t->sighand->action[i].sa.sa_handler = SIG_IGN;
  218 +
  219 + flush_signals(t);
  220 +}
  221 +
212 222 /*
213 223 * Flush all handlers for a task.
214 224 */