From patchwork Sun Sep 18 15:05:10 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 9337911 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 25EC5601C2 for ; Sun, 18 Sep 2016 15:05:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 180D928CDF for ; Sun, 18 Sep 2016 15:05:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0CE6B28CEE; Sun, 18 Sep 2016 15:05:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B94428CDF for ; Sun, 18 Sep 2016 15:05:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936274AbcIRPFn (ORCPT ); Sun, 18 Sep 2016 11:05:43 -0400 Received: from thejh.net ([37.221.195.125]:46260 "EHLO thejh.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933938AbcIRPFd (ORCPT ); Sun, 18 Sep 2016 11:05:33 -0400 Received: from pc.thejh.net (pc.vpn [192.168.44.2]) by thejh.net (Postfix) with ESMTPSA id 233671823B5; Sun, 18 Sep 2016 17:05:31 +0200 (CEST) From: Jann Horn To: Alexander Viro , Roland McGrath , Oleg Nesterov , John Johansen , James Morris , "Serge E. Hallyn" , Paul Moore , Stephen Smalley , Eric Paris , Casey Schaufler , Kees Cook , Andrew Morton , Janis Danisevskis , Seth Forshee , "Eric . Biederman" , Thomas Gleixner , Benjamin LaHaise Cc: linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, security@kernel.org Subject: [PATCH 2/9] exec: turn self_exec_id into self_privunit_id Date: Sun, 18 Sep 2016 17:05:10 +0200 Message-Id: <1474211117-16674-3-git-send-email-jann@thejh.net> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1474211117-16674-1-git-send-email-jann@thejh.net> References: <1474211117-16674-1-git-send-email-jann@thejh.net> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This ensures that self_privunit_id ("privilege unit ID") is only shared by processes that share the mm_struct and the signal_struct; not just spatially, but also temporally. In other words, if you do execve() or clone() without CLONE_THREAD, you get a new privunit_id that has never been used before. One reason for doing this is that it prevents an attacker from sending an arbitrary signal to a parent process after performing 2^32-1 execve() calls. The second reason for this is that it permits using the self_exec_id in a later patch to check during a ptrace access whether subject and object are temporally and spatially equal for privilege checking purposes. This patch was grabbed from grsecurity and modified. Credit for the original patch goes to Brad Spengler . Signed-off-by: Jann Horn --- fs/exec.c | 21 ++++++++++++++++++++- include/linux/binfmts.h | 1 + include/linux/sched.h | 4 ++-- kernel/fork.c | 5 +++-- kernel/signal.c | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 84430ee..1a15cb0 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1281,6 +1281,25 @@ void would_dump(struct linux_binprm *bprm, struct file *file) } EXPORT_SYMBOL(would_dump); +static DEFINE_PER_CPU(u64, exec_counter); +static int __init init_exec_counters(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) { + per_cpu(exec_counter, cpu) = (u64)cpu; + } + + return 0; +} +early_initcall(init_exec_counters); + +void increment_privunit_counter(void) +{ + BUILD_BUG_ON(NR_CPUS > (1 << 16)); + current->self_privunit_id = this_cpu_add_return(exec_counter, NR_CPUS); +} + void setup_new_exec(struct linux_binprm * bprm) { arch_pick_mmap_layout(current->mm); @@ -1314,7 +1333,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++; + increment_privunit_counter(); flush_signal_handlers(current, 0); do_close_on_exec(current->files); } diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 1303b57..9570bd0 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -100,6 +100,7 @@ extern int prepare_binprm(struct linux_binprm *); extern int __must_check remove_arg_zero(struct linux_binprm *); extern int search_binary_handler(struct linux_binprm *); extern int flush_old_exec(struct linux_binprm * bprm); +extern void increment_privunit_counter(void); extern void setup_new_exec(struct linux_binprm * bprm); extern void would_dump(struct linux_binprm *, struct file *); diff --git a/include/linux/sched.h b/include/linux/sched.h index 2a1df2f..e4bf894 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1688,8 +1688,8 @@ struct task_struct { struct seccomp seccomp; /* Thread group tracking */ - u32 parent_exec_id; - u32 self_exec_id; + u64 parent_privunit_id; + u64 self_privunit_id; /* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, * mempolicy */ spinlock_t alloc_lock; diff --git a/kernel/fork.c b/kernel/fork.c index 2d46f3a..537c117 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1567,6 +1567,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->exit_signal = (clone_flags & CSIGNAL); p->group_leader = p; p->tgid = p->pid; + increment_privunit_counter(); } p->nr_dirtied = 0; @@ -1597,10 +1598,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, /* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { p->real_parent = current->real_parent; - p->parent_exec_id = current->parent_exec_id; + p->parent_privunit_id = current->parent_privunit_id; } else { p->real_parent = current; - p->parent_exec_id = current->self_exec_id; + p->parent_privunit_id = current->self_privunit_id; } spin_lock(¤t->sighand->siglock); diff --git a/kernel/signal.c b/kernel/signal.c index af21afc..e4e3e1b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1590,7 +1590,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) * This is only possible if parent == real_parent. * Check if it has changed security domain. */ - if (tsk->parent_exec_id != tsk->parent->self_exec_id) + if (tsk->parent_privunit_id != tsk->parent->self_privunit_id) sig = SIGCHLD; }