From patchwork Thu Oct 19 21:36:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10018333 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 828D760224 for ; Thu, 19 Oct 2017 21:36:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 75B0428E6C for ; Thu, 19 Oct 2017 21:36:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6A52D28E6E; Thu, 19 Oct 2017 21:36:43 +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=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 4E9CD28E6C for ; Thu, 19 Oct 2017 21:36:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751496AbdJSVgl (ORCPT ); Thu, 19 Oct 2017 17:36:41 -0400 Received: from mail-oi0-f73.google.com ([209.85.218.73]:59099 "EHLO mail-oi0-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750977AbdJSVgl (ORCPT ); Thu, 19 Oct 2017 17:36:41 -0400 Received: by mail-oi0-f73.google.com with SMTP id h6so9169171oia.17 for ; Thu, 19 Oct 2017 14:36:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:date:message-id:subject:from:to:cc; bh=1GKVudTDNV1L/m2551mSHbrimDEOXCFS1b/A1eXWPiA=; b=asoCrtCXVjpKsgLxSNBN7PyyCHhWQ4zvS+OA6RPYhYX5KAsc34DuUUB0ulzRbvYXgs JgtJXMYenPt+hPEhEbT8DQiTKpa230oiW+jfkUjSquYGngUT82X4EA2Nbg8Wijq2lHtp UcUiMkCdMfSQimu5HNTrhhq5sG1SuYyA8FBKCWi5YVoFEV4tNNa9VqtSqBFmZX6mCxTl OhwmRXvzgJ9oh27WF/Luu+ZbSzctUvLl3+vB2zr5Cmk3fsvGw6sYldMnlxiQ3No91vil PQFtflUTmUeT72LqY5udZvd4jGECZR8saeb6NtG1aPdOfJ7JbKl69N94d4VZyxn1b8Gy ReEQ== 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:message-id:subject:from:to:cc; bh=1GKVudTDNV1L/m2551mSHbrimDEOXCFS1b/A1eXWPiA=; b=KDYT3Tnyk8TS8cJdgEM30aaaYe1J1VMXocVRhdBIRomXEVdd2tmPYt3SLokXm37XV4 cPe0pqEckjubB85ZxB90X38Kt1h/rWvyawr/TU7RNvFvkfg77ebCv1xYj7McjoRcxEoW pBruTMl6mghupe13hjdh9zhrHkZiw+ryPkr+KT81DNZKIC7tcMbWNi3k982aAeFOLmHN LmyARqD+kd/wuEGtrYz7iBfeZxEJA/oTUsZb0+vkvM0R5JSRnS/j81TsLsIe2oYMXViq da+5hcwOwFKbG6F+3AUbhXSGgJYDwVpt0KvcylXxkftsgkuxW7fQo4SVSGcfGM7MhhSI HPKQ== X-Gm-Message-State: AMCzsaXfsq77GFT09TmnYonNWeX89VDSXObXZ6VGhctEfdNMKT0kLNOf GMJb8GZyCPz49WHqrRd2zYPzmytwGpXrB6BTHqbHF6q2Qe/QgvCKlUknaBB6JbuJXPxDa04CrF+ J1eHDZ3McsY80bnajBwle2XiMcI68neYnZx0= X-Google-Smtp-Source: ABhQp+Sd2bKvavnF/+4zt4iMvqa3kvpWlQZgEPmsNKVDGYQ50kGjCaJ+uEmAt6pZ8WKn3Mju7siijiGhaJLLjxEE+YiFVg== MIME-Version: 1.0 X-Received: by 10.157.89.15 with SMTP id t15mr1537201oth.17.1508449000352; Thu, 19 Oct 2017 14:36:40 -0700 (PDT) Date: Thu, 19 Oct 2017 14:36:36 -0700 Message-Id: <20171019213636.17264-1-mjg59@google.com> X-Mailer: git-send-email 2.15.0.rc0.271.g36b669edcc-goog Subject: [PATCH V2] EVM: Add support for portable signature format From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, Matthew Garrett , Dmitry Kasatkin , Mikhail Kurinnoi 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 EVM signature includes the inode number and (optionally) the filesystem UUID, making it impractical to ship EVM signatures in packages. This patch adds a new portable format intended to allow distributions to include EVM signatures. It is identical to the existing format but hardcodes the inode and generation numbers to 0 and does not include the filesystem UUID even if the kernel is configured to do so. Removing the inode means that the metadata and signature from one file could be copied to another file without invalidating it. This is avoided by only permitting signatures in this format to be used when IMA appraisal is supported, and ensuring that an IMA xattr is present during EVM validation. Based on earlier work by Dmitry Kasatkin and Mikhail Kurinnoi. Signed-off-by: Matthew Garrett Cc: Dmitry Kasatkin Cc: Mikhail Kurinnoi --- security/integrity/evm/evm.h | 2 +- security/integrity/evm/evm_crypto.c | 37 ++++++++++++++++++++++++++++--------- security/integrity/evm/evm_main.c | 12 ++++++++++-- security/integrity/integrity.h | 1 + 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index f5f12727771a..2ff02459fcfd 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -48,7 +48,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, size_t req_xattr_value_len, 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, char type, 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..8855722529d4 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) + char type, char *digest) { struct h_misc { unsigned long ino; @@ -149,8 +149,13 @@ 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; + /* Don't include the inode or generation number in portable + * signatures + */ + if (type != EVM_XATTR_PORTABLE_DIGSIG) { + 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 @@ -163,7 +168,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); 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 ((evm_hmac_attrs & EVM_ATTR_FSUUID) && + type != EVM_XATTR_PORTABLE_DIGSIG) crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0], sizeof(inode->i_sb->s_uuid)); crypto_shash_final(desc, digest); @@ -189,6 +195,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, char *xattr_value = NULL; int error; int size; + bool ima_present = false; if (!(inode->i_opflags & IOP_XATTR)) return -EOPNOTSUPP; @@ -199,11 +206,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, error = -ENODATA; for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { + bool is_ima = false; + + if (strcmp(*xattrname, XATTR_NAME_IMA) == 0) + is_ima = true; + if ((req_xattr_name && req_xattr_value) && !strcmp(*xattrname, req_xattr_name)) { error = 0; crypto_shash_update(desc, (const u8 *)req_xattr_value, req_xattr_value_len); + if (is_ima) + ima_present = true; continue; } size = vfs_getxattr_alloc(dentry, *xattrname, @@ -218,9 +232,14 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, error = 0; xattr_size = size; crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size); + if (is_ima) + ima_present = true; } - hmac_add_misc(desc, inode, digest); + hmac_add_misc(desc, inode, type, digest); + /* Portable EVM signatures must include an IMA hash */ + if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present) + return -EPERM; out: kfree(xattr_value); kfree(desc); @@ -232,15 +251,15 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, 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, 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) + char type, 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, type, digest); } /* @@ -280,7 +299,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_XATTR_HMAC, hmac_val); kfree(desc); return 0; } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 063d38aef64e..f29ac3384b2a 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -161,8 +161,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, rc = -EINVAL; break; case EVM_IMA_XATTR_DIGSIG: + /* Portable signatures could be applied to arbitrary files if they + * don't contain IMA hashes, so only support them when IMA is enabled + */ +#ifdef CONFIG_IMA_APPRAISE + case EVM_XATTR_PORTABLE_DIGSIG: +#endif rc = evm_calc_hash(dentry, xattr_name, xattr_value, - xattr_value_len, calc.digest); + xattr_value_len, xattr_data->type, + calc.digest); if (rc) break; rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, @@ -345,7 +352,8 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { if (!xattr_value_len) return -EINVAL; - if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) + if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && + xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) return -EPERM; } return evm_protect_xattr(dentry, xattr_name, xattr_value, diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index a53e7e4ab06c..1e268ca9706f 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -58,6 +58,7 @@ enum evm_ima_xattr_type { EVM_XATTR_HMAC, EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, + EVM_XATTR_PORTABLE_DIGSIG, IMA_XATTR_LAST };