Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10ab825b authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds
Browse files

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: default avatarOleg Nesterov <oleg@tv-sign.ru>
Acked-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5de18d16
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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;
+3 −14
Original line number Diff line number Diff line
@@ -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)
+10 −0
Original line number Diff line number Diff line
@@ -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.
 */