From patchwork Tue Jul 18 22:25:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9849925 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 5257B600CC for ; Tue, 18 Jul 2017 22:26:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C93B28433 for ; Tue, 18 Jul 2017 22:26:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3127D285B7; Tue, 18 Jul 2017 22:26:13 +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=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, 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 8BE8228433 for ; Tue, 18 Jul 2017 22:26:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752732AbdGRWZ6 (ORCPT ); Tue, 18 Jul 2017 18:25:58 -0400 Received: from mail-pg0-f49.google.com ([74.125.83.49]:33601 "EHLO mail-pg0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752542AbdGRWZt (ORCPT ); Tue, 18 Jul 2017 18:25:49 -0400 Received: by mail-pg0-f49.google.com with SMTP id k14so19995282pgr.0 for ; Tue, 18 Jul 2017 15:25:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=E2HY5QSH2LDQQrw+F9kjlO10AtH/8rLMoS1KBYK2k8s=; b=E0EFjwpeDf6RWzo5tTOT3tz1GqIBapI65oVi2/R0HY3DorfS1Ob24RYr1Ysf5p7k0P tuDmxWlWvL2gvNG4TFYbYzCN05mz7t5/18l152Fnf2CC5grhobFpMccigATsqMeKRsJq hdZdT1bqykzFfiMyt0m7dPrFcMMG1rRLkQoCk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=E2HY5QSH2LDQQrw+F9kjlO10AtH/8rLMoS1KBYK2k8s=; b=Vgrf40n+P2hDpNutk5QmR5LZinSLkTp0usgHYV6+84EgWT9w6tornPFuZmZl/fIa91 gVBqAUwd2qVijANGdnAP5F4d0YejR0/LpQqNoEYb4ym6kI2wsFMHYc26p60Id8egVXm3 fLDP3zXf6XyQXdLQEitz3tIPc6ymM5L5L8JnAQ14skws7cWaGS/LsdcLgv+9367ufnFk NpywudeWy16wPTymfr0sWyqFTZAC2WRRrrQEC27fBupkqJTwWyjU3sUJ8vvrOJsxgQLv G9w8j1ZGvyKXSKEWuGsu3DVBBKQadtNa8CYT8V8KWQpKclcXBJEkpdeIgVEsLAdJRyGH Aozw== X-Gm-Message-State: AIVw111r3/zD+Rv+kKzSgvO3bXYO8TIsTYqQFcnmzfHggJqb4ymQIhHq inwbpY5Ugm07OxxA X-Received: by 10.101.85.79 with SMTP id t15mr3877961pgr.95.1500416749030; Tue, 18 Jul 2017 15:25:49 -0700 (PDT) Received: from www.outflux.net (173-164-112-133-Oregon.hfc.comcastbusiness.net. [173.164.112.133]) by smtp.gmail.com with ESMTPSA id o7sm6156402pgf.63.2017.07.18.15.25.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 18 Jul 2017 15:25:47 -0700 (PDT) From: Kees Cook To: Andrew Morton Cc: Kees Cook , Serge Hallyn , Andy Lutomirski , David Howells , "Eric W. Biederman" , John Johansen , Paul Moore , Stephen Smalley , Casey Schaufler , Tetsuo Handa , James Morris , Linus Torvalds , linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 06/15] commoncap: Refactor to remove bprm_secureexec hook Date: Tue, 18 Jul 2017 15:25:27 -0700 Message-Id: <1500416736-49829-7-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1500416736-49829-1-git-send-email-keescook@chromium.org> References: <1500416736-49829-1-git-send-email-keescook@chromium.org> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The commoncap implementation of the bprm_secureexec hook is the only LSM that depends on the final call to its bprm_set_creds hook (since it may be called for multiple files, it ignores bprm->called_set_creds). As a result, it cannot safely _clear_ bprm->secureexec since other LSMs may have set it. Instead, remove the bprm_secureexec hook by introducing a new flag to bprm specific to commoncap: cap_elevated. This is similar to cap_effective, but that is used for a specific subset of elevated privileges, and exists solely to track state from bprm_set_creds to bprm_secureexec. As such, it will be removed in the next patch. Here, set the new bprm->cap_elevated flag when setuid/setgid has happened from bprm_fill_uid() or fscapabilities have been prepared. This temporarily moves the bprm_secureexec hook to a static inline. The helper will be removed in the next patch; this makes the step easier to review and bisect, since this does not introduce any changes to inputs nor outputs to the "elevated privileges" calculation. The new flag is merged with the bprm->secureexec flag in setup_new_exec() since this marks the end of any further prepare_binprm() calls. Cc: Serge Hallyn Cc: Andy Lutomirski Signed-off-by: Kees Cook Reviewed-by: Andy Lutomirski Acked-by: James Morris --- fs/exec.c | 7 +++++++ include/linux/binfmts.h | 7 +++++++ security/commoncap.c | 12 ++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 925c85a45d97..53ffa739fb58 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1330,6 +1330,13 @@ EXPORT_SYMBOL(would_dump); void setup_new_exec(struct linux_binprm * bprm) { + /* + * Once here, prepare_binrpm() will not be called any more, so + * the final state of setuid/setgid/fscaps can be merged into the + * secureexec flag. + */ + bprm->secureexec |= bprm->cap_elevated; + arch_pick_mmap_layout(current->mm); /* This is the point of no return */ diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 36be5a67517a..a82f5edf23f9 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -35,6 +35,13 @@ struct linux_binprm { * false if not; except for init which inherits * its parent's caps anyway */ /* + * True if most recent call to the commoncaps bprm_set_creds + * hook (due to multiple prepare_binprm() calls from the + * binfmt_script/misc handlers) resulted in elevated + * privileges. + */ + cap_elevated:1, + /* * Set by bprm_set_creds hook to indicate a privilege-gaining * exec has happened. Used to sanitize execution environment * and to set AT_SECURE auxv for glibc. diff --git a/security/commoncap.c b/security/commoncap.c index 7abebd782d5e..abb6050c8083 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -481,6 +481,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c return rc; } +static int is_secureexec(struct linux_binprm *bprm); + /** * cap_bprm_set_creds - Set up the proposed credentials for execve(). * @bprm: The execution parameters, including the proposed creds @@ -614,11 +616,14 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) if (WARN_ON(!cap_ambient_invariant_ok(new))) return -EPERM; + /* Check for privilege-elevated exec. */ + bprm->cap_elevated = is_secureexec(bprm); + return 0; } /** - * cap_bprm_secureexec - Determine whether a secure execution is required + * is_secureexec - Determine whether a secure execution is required * @bprm: The execution parameters * * Determine whether a secure execution is required, return 1 if it is, and 0 @@ -627,9 +632,9 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) * The credentials have been committed by this point, and so are no longer * available through @bprm->cred. */ -int cap_bprm_secureexec(struct linux_binprm *bprm) +static int is_secureexec(struct linux_binprm *bprm) { - const struct cred *cred = current_cred(); + const struct cred *cred = bprm->cred; kuid_t root_uid = make_kuid(cred->user_ns, 0); if (!uid_eq(cred->uid, root_uid)) { @@ -1079,7 +1084,6 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(capget, cap_capget), LSM_HOOK_INIT(capset, cap_capset), LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), - LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec), LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),