From patchwork Wed Sep 27 22:16:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 9974981 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 DD64260375 for ; Wed, 27 Sep 2017 22:17:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CFDF5204FA for ; Wed, 27 Sep 2017 22:17:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C4C94204FE; Wed, 27 Sep 2017 22:17:10 +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.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=ham 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 16553204FA for ; Wed, 27 Sep 2017 22:17:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752237AbdI0WRJ (ORCPT ); Wed, 27 Sep 2017 18:17:09 -0400 Received: from mail-it0-f74.google.com ([209.85.214.74]:48442 "EHLO mail-it0-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752171AbdI0WRJ (ORCPT ); Wed, 27 Sep 2017 18:17:09 -0400 Received: by mail-it0-f74.google.com with SMTP id g18so14677itg.7 for ; Wed, 27 Sep 2017 15:17:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:date:in-reply-to:message-id:references:subject:from:to :cc; bh=hCZCwU58la8Eurui8tsLoEZo0cMJuhQOlYTK5n5CTfw=; b=Z86056MXs5bDVQiUgLd+beqsqldx5W6T/w+QpT/bidwRsp0joSZ1Ub4q0lyn6PeTTC +bWzkRv2n7bRjb60I5ZQO+660THpMUdQSxiI2PXEQof2EEEwC4cSgzV0sUJHxf+oYhIR bUK0QFiybMWUypuVazzk0ty4oqGqWOQ6JAeueNJZosXxSuSZ/T9vuz2INwe0feCW8sNT E4zLRimx+Xy71xUuCVs01Q773VhFcK33T9BBuXHvhsOpjlsaZ8TnnZ6Z/dGlAJ8QvBn9 eCTi5JFDSPQ9S793hWDQA59PPdihYkaEHSTjKzP5hIXkvllAsyS2taMWCQtXDJOEqZrE uQWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:date:in-reply-to:message-id :references:subject:from:to:cc; bh=hCZCwU58la8Eurui8tsLoEZo0cMJuhQOlYTK5n5CTfw=; b=ojTrDFocGv7StUcw/qN2zC1KfQRmEA3xG0txi6HGFPWX/5zIgD8+2ne1t1PsKyV9o+ fFwQo/jxshYtBFgnV5R29SoemI89n1u6sAi4BGaUnnFC1Ab+1ho4pir7IImqaV81B03l WgIVhXWj89h7K7O4YXJRCXzHf6YpikdX+WdmuGYFm+cYViX0u1Q9uGvyC/pPP9HXlCFU 4w+4vUz+qH1jIbTzs0MREovkLvF7eP2sO591W9GQzTey0HlWbmM422ScrnFMuzqarBRn FPWqAGN9ymokwDgCpBnFKgecdpSGD/RMzX4Q6ocVoBe/e1zv5iclQm/gUCCKS5DpoFTX advw== X-Gm-Message-State: AHPjjUiQSG9+qMwug+oy8o9ZWFbrxHal3lf5hJDccTM6dJoOLOnf9bz5 QJZF8f/vJLi3I3LmOwck/V8OaAo+uTmT1Zey5VztJGe+djC+xODjh6MydCUAA+FCauk4mcM1rPx H5XGV1494/zG0iCoUk5R8aNSQ8mikZM2SpRM= X-Google-Smtp-Source: AOwi7QA0e4t32Jnl9eocACH9ZENbJOGrljuVrVws5ZIbw99noFTSsPnAyjAHR2YcBsZbtwF+tquv8nCxFFwPviMi67PHSQ== MIME-Version: 1.0 X-Received: by 10.36.39.141 with SMTP id g135mr1611297ita.6.1506550628354; Wed, 27 Sep 2017 15:17:08 -0700 (PDT) Date: Wed, 27 Sep 2017 15:16:49 -0700 In-Reply-To: <20170927221653.11219-1-mjg59@google.com> Message-Id: <20170927221653.11219-3-mjg59@google.com> References: <20170927221653.11219-1-mjg59@google.com> X-Mailer: git-send-email 2.14.2.822.g60be5d43e6-goog Subject: [PATCH 2/6] EVM: Add infrastructure for making EVM fields optional From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The set of information used for EVM calculations is currently hardcoded at kernel build time. Add infrastructure for allowing individual components to be enabled or disabled, but keep the same default behaviour for the moment. Signed-off-by: Matthew Garrett --- security/integrity/evm/evm.h | 22 +++++++++++++---- security/integrity/evm/evm_crypto.c | 48 ++++++++++++++++++++++--------------- security/integrity/evm/evm_main.c | 45 +++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index f5f12727771a..1d8201b1fb8a 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -28,9 +28,23 @@ extern int evm_initialized; extern char *evm_hmac; extern char *evm_hash; -#define EVM_ATTR_FSUUID 0x0001 +/* Extended attributes */ +#define EVM_SELINUX (1L << 0) +#define EVM_SMACK (1L << 1) +#define EVM_SMACKEXEC (1L << 2) +#define EVM_SMACKTRANSMUTE (1L << 3) +#define EVM_SMACKMMAP (1L << 4) +#define EVM_IMA (1L << 5) +#define EVM_CAPS (1L << 6) +/* Other metadata */ +#define EVM_INODE (1L << 32) +#define EVM_OWNERSHIP (1L << 33) +#define EVM_MODE (1L << 34) +#define EVM_FSUUID (1L << 35) +/* Behavioural flags */ +#define EVM_HMAC_CONVERT (1L << 63) -extern int evm_hmac_attrs; +extern u64 evm_default_flags; extern struct crypto_shash *hmac_tfm; extern struct crypto_shash *hash_tfm; @@ -45,10 +59,10 @@ int evm_update_evmxattr(struct dentry *dentry, size_t req_xattr_value_len); int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); + size_t req_xattr_value_len, u64 flags, char *digest); int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); + size_t req_xattr_value_len, u64 flags, char *digest); int evm_init_hmac(struct inode *inode, const struct xattr *xattr, char *hmac_val); int evm_init_secfs(void); diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 1d32cd20009a..9ce55ac6781e 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -138,7 +138,7 @@ static struct shash_desc *init_desc(char type) * protection.) */ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, - char *digest) + u64 flags, char *digest) { struct h_misc { unsigned long ino; @@ -149,8 +149,10 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, } hmac_misc; memset(&hmac_misc, 0, sizeof(hmac_misc)); - hmac_misc.ino = inode->i_ino; - hmac_misc.generation = inode->i_generation; + if (flags & EVM_INODE) { + hmac_misc.ino = inode->i_ino; + hmac_misc.generation = inode->i_generation; + } /* The hmac uid and gid must be encoded in the initial user * namespace (not the filesystems user namespace) as encoding * them in the filesystems user namespace allows an attack @@ -159,11 +161,14 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, * filesystem for real on next boot and trust it because * everything is signed. */ - hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); - hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); - hmac_misc.mode = inode->i_mode; + if (flags & EVM_OWNERSHIP) { + hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); + hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); + } + if (flags & EVM_MODE) + hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); - if (evm_hmac_attrs & EVM_ATTR_FSUUID) + if (flags & EVM_FSUUID) crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0], sizeof(inode->i_sb->s_uuid)); crypto_shash_final(desc, digest); @@ -180,15 +185,16 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char type, char *digest) + char type, u64 flags, char *digest) { struct inode *inode = d_backing_inode(dentry); struct shash_desc *desc; - char **xattrname; + char *xattrname; size_t xattr_size = 0; char *xattr_value = NULL; int error; int size; + int i; if (!(inode->i_opflags & IOP_XATTR)) return -EOPNOTSUPP; @@ -198,15 +204,19 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, return PTR_ERR(desc); error = -ENODATA; - for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { + for (i = 0; evm_config_xattrnames[i] != NULL; i++) { + if (!(flags & (1 << i))) + continue; + + xattrname = evm_config_xattrnames[i]; if ((req_xattr_name && req_xattr_value) - && !strcmp(*xattrname, req_xattr_name)) { + && !strcmp(xattrname, req_xattr_name)) { error = 0; crypto_shash_update(desc, (const u8 *)req_xattr_value, req_xattr_value_len); continue; } - size = vfs_getxattr_alloc(dentry, *xattrname, + size = vfs_getxattr_alloc(dentry, xattrname, &xattr_value, xattr_size, GFP_NOFS); if (size == -ENOMEM) { error = -ENOMEM; @@ -219,7 +229,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, xattr_size = size; crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size); } - hmac_add_misc(desc, inode, digest); + hmac_add_misc(desc, inode, flags, digest); out: kfree(xattr_value); @@ -229,18 +239,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char *digest) + u64 flags, char *digest) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, EVM_XATTR_HMAC, digest); + req_xattr_value_len, EVM_XATTR_HMAC, flags, digest); } int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char *digest) + u64 flags, char *digest) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, IMA_XATTR_DIGEST, digest); + req_xattr_value_len, IMA_XATTR_DIGEST, flags, digest); } /* @@ -256,7 +266,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, int rc = 0; rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, xattr_data.digest); + xattr_value_len, evm_default_flags, xattr_data.digest); if (rc == 0) { xattr_data.type = EVM_XATTR_HMAC; rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, @@ -280,7 +290,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, } crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len); - hmac_add_misc(desc, inode, hmac_val); + hmac_add_misc(desc, inode, evm_default_flags, hmac_val); kfree(desc); return 0; } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 44e4f4fda965..52b6fff91f8d 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -35,23 +35,32 @@ static char *integrity_status_msg[] = { }; char *evm_hmac = "hmac(sha1)"; char *evm_hash = "sha1"; -int evm_hmac_attrs; -char *evm_config_xattrnames[] = { +u64 evm_default_flags = #ifdef CONFIG_SECURITY_SELINUX - XATTR_NAME_SELINUX, + EVM_SELINUX | #endif #ifdef CONFIG_SECURITY_SMACK - XATTR_NAME_SMACK, + EVM_SMACK | #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS - XATTR_NAME_SMACKEXEC, - XATTR_NAME_SMACKTRANSMUTE, - XATTR_NAME_SMACKMMAP, + EVM_SMACKEXEC | EVM_SMACKTRANSMUTE | EVM_SMACKMMAP | #endif #endif #ifdef CONFIG_IMA_APPRAISE - XATTR_NAME_IMA, + EVM_IMA | #endif +#ifdef CONFIG_EVM_ATTR_FSUUID + EVM_FSUUID | +#endif + EVM_CAPS | EVM_INODE | EVM_OWNERSHIP | EVM_MODE; + +char *evm_config_xattrnames[] = { + XATTR_NAME_SELINUX, + XATTR_NAME_SMACK, + XATTR_NAME_SMACKEXEC, + XATTR_NAME_SMACKTRANSMUTE, + XATTR_NAME_SMACKMMAP, + XATTR_NAME_IMA, XATTR_NAME_CAPS, NULL }; @@ -67,24 +76,26 @@ __setup("evm=", evm_set_fixmode); static void __init evm_init_config(void) { -#ifdef CONFIG_EVM_ATTR_FSUUID - evm_hmac_attrs |= EVM_ATTR_FSUUID; -#endif - pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); + pr_info("HMAC attrs: 0x%llx\n", evm_default_flags); } static int evm_find_protected_xattrs(struct dentry *dentry) { struct inode *inode = d_backing_inode(dentry); - char **xattr; + char *xattr; int error; int count = 0; + int i; if (!(inode->i_opflags & IOP_XATTR)) return -EOPNOTSUPP; - for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { - error = __vfs_getxattr(dentry, inode, *xattr, NULL, 0); + for (i = 0; evm_config_xattrnames[i] != NULL; i++) { + if (!(evm_default_flags & (1 << i))) + continue; + + xattr = evm_config_xattrnames[i]; + error = __vfs_getxattr(dentry, inode, xattr, NULL, 0); if (error < 0) { if (error == -ENODATA) continue; @@ -152,7 +163,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, goto out; } rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, calc.digest); + xattr_value_len, evm_default_flags, calc.digest); if (rc) break; rc = crypto_memneq(xattr_data->digest, calc.digest, @@ -162,7 +173,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, break; case EVM_IMA_XATTR_DIGSIG: rc = evm_calc_hash(dentry, xattr_name, xattr_value, - xattr_value_len, calc.digest); + xattr_value_len, evm_default_flags, calc.digest); if (rc) break; rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,