Add exec_id to signal_struct and compare it at a few choice moments. I believe this closes the security holes that letting the zombie threads linger after exec opens up. The problem is that old threads may have different creds after a setuid exec, and then formerly shared resources may change. So signal sending and accesses by proc need to be blocked. Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> --- fs/exec.c | 1 + include/linux/sched/signal.h | 1 + kernel/fork.c | 1 + kernel/ptrace.c | 4 ++++ kernel/signal.c | 7 ++++++- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/exec.c b/fs/exec.c index 303a114b00ce..730dee8bb2f8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1323,6 +1323,7 @@ void setup_new_exec(struct linux_binprm * bprm) /* An exec changes our domain. We are no longer part of the thread group */ current->self_exec_id++; + current->signal->exec_id = current->self_exec_id; flush_signal_handlers(current, 0); } EXPORT_SYMBOL(setup_new_exec); diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 2cf446704cd4..63ae951ee330 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -80,6 +80,7 @@ struct signal_struct { atomic_t live; int nr_threads; struct list_head thread_head; + u32 exec_id; wait_queue_head_t wait_chldexit; /* for wait4() */ diff --git a/kernel/fork.c b/kernel/fork.c index 0632ac1180be..a442fa099842 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1387,6 +1387,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->oom_score_adj = current->signal->oom_score_adj; sig->oom_score_adj_min = current->signal->oom_score_adj_min; + sig->exec_id = current->self_exec_id; mutex_init(&sig->cred_guard_mutex); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0af928712174..cc6b10b1ffbe 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -277,6 +277,10 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) * or halting the specified task is impossible. */ + /* Don't allow inspecting a thread after exec */ + if (task->self_exec_id != task->signal->exec_id) + return 1; + /* Don't let security modules deny introspection */ if (same_thread_group(task, current)) return 0; diff --git a/kernel/signal.c b/kernel/signal.c index fd75ba33ee3d..fe8dcdb622f5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -995,6 +995,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, from_ancestor_ns || (info == SEND_SIG_FORCED))) goto ret; + /* Don't allow thread group signals after exec */ + if (group && (t->signal->exec_id != t->self_exec_id)) + goto ret; + pending = group ? &t->signal->shared_pending : &t->pending; /* * Short-circuit ignored signals and support queuing @@ -1247,7 +1251,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, * must see ->sighand == NULL. */ spin_lock(&sighand->siglock); - if (likely(sighand == tsk->sighand)) { + if (likely((sighand == tsk->sighand) && + (tsk->self_exec_id == tsk->signal->exec_id))) { rcu_read_unlock(); break; } -- 2.10.1 -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html