diff options
Diffstat (limited to 'security/integrity/evm/evm_crypto.c')
| -rw-r--r-- | security/integrity/evm/evm_crypto.c | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index fa5ff13fa8c9..a5e730ffda57 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -40,7 +40,7 @@ static const char evm_hmac[] = "hmac(sha1)"; /** * evm_set_key() - set EVM HMAC key from the kernel * @key: pointer to a buffer with the key data - * @size: length of the key data + * @keylen: length of the key data * * This function allows setting the EVM HMAC key from the kernel * without using the "encrypted" key subsystem keys. It can be used @@ -180,11 +180,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, } /* - * Dump large security xattr values as a continuous ascii hexademical string. + * Dump large security xattr values as a continuous ascii hexadecimal string. * (pr_debug is limited to 64 bytes.) */ -static void dump_security_xattr(const char *prefix, const void *src, - size_t count) +static void dump_security_xattr_l(const char *prefix, const void *src, + size_t count) { #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) char *asciihex, *p; @@ -200,6 +200,16 @@ static void dump_security_xattr(const char *prefix, const void *src, #endif } +static void dump_security_xattr(const char *name, const char *value, + size_t value_len) +{ + if (value_len < 64) + pr_debug("%s: (%zu) [%*phN]\n", name, value_len, + (int)value_len, value); + else + dump_security_xattr_l(name, value, value_len); +} + /* * Calculate the HMAC value across the set of protected security xattrs. * @@ -211,9 +221,10 @@ 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, - uint8_t type, struct evm_digest *data) + uint8_t type, struct evm_digest *data, + struct evm_iint_cache *iint) { - struct inode *inode = d_backing_inode(dentry); + struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA)); struct xattr_list *xattr; struct shash_desc *desc; size_t xattr_size = 0; @@ -221,6 +232,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, int error; int size, user_space_size; bool ima_present = false; + u64 i_version = 0; if (!(inode->i_opflags & IOP_XATTR) || inode->i_sb->s_user_ns != &init_user_ns) @@ -254,18 +266,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, if (is_ima) ima_present = true; - if (req_xattr_value_len < 64) - pr_debug("%s: (%zu) [%*phN]\n", req_xattr_name, - req_xattr_value_len, - (int)req_xattr_value_len, - req_xattr_value); - else - dump_security_xattr(req_xattr_name, - req_xattr_value, - req_xattr_value_len); + dump_security_xattr(req_xattr_name, + req_xattr_value, + req_xattr_value_len); continue; } - size = vfs_getxattr_alloc(&init_user_ns, dentry, xattr->name, + size = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, xattr->name, &xattr_value, xattr_size, GFP_NOFS); if (size == -ENOMEM) { error = -ENOMEM; @@ -274,7 +280,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, if (size < 0) continue; - user_space_size = vfs_getxattr(&init_user_ns, dentry, + user_space_size = vfs_getxattr(&nop_mnt_idmap, dentry, xattr->name, NULL, 0); if (user_space_size != size) pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n", @@ -286,15 +292,17 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, if (is_ima) ima_present = true; - if (xattr_size < 64) - pr_debug("%s: (%zu) [%*phN]", xattr->name, xattr_size, - (int)xattr_size, xattr_value); - else - dump_security_xattr(xattr->name, xattr_value, - xattr_size); + dump_security_xattr(xattr->name, xattr_value, xattr_size); } hmac_add_misc(desc, inode, type, data->digest); + if (inode != d_backing_inode(dentry) && iint) { + if (IS_I_VERSION(inode)) + i_version = inode_query_iversion(inode); + integrity_inode_attrs_store(&iint->metadata_inode, i_version, + inode); + } + /* Portable EVM signatures must include an IMA hash */ if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present) error = -EPERM; @@ -306,32 +314,33 @@ out: int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - struct evm_digest *data) + struct evm_digest *data, struct evm_iint_cache *iint) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, EVM_XATTR_HMAC, data); + req_xattr_value_len, EVM_XATTR_HMAC, data, + iint); } int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char type, struct evm_digest *data) + char type, struct evm_digest *data, struct evm_iint_cache *iint) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, type, data); + req_xattr_value_len, type, data, iint); } static int evm_is_immutable(struct dentry *dentry, struct inode *inode) { const struct evm_ima_xattr_data *xattr_data = NULL; - struct integrity_iint_cache *iint; + struct evm_iint_cache *iint; int rc = 0; - iint = integrity_iint_find(inode); + iint = evm_iint_inode(inode); if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG)) return 1; /* Do this the hard way */ - rc = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_EVM, + rc = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0, GFP_NOFS); if (rc <= 0) { if (rc == -ENODATA) @@ -358,6 +367,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, const char *xattr_value, size_t xattr_value_len) { struct inode *inode = d_backing_inode(dentry); + struct evm_iint_cache *iint = evm_iint_inode(inode); struct evm_digest data; int rc = 0; @@ -373,23 +383,24 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, data.hdr.algo = HASH_ALGO_SHA1; rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, &data); + xattr_value_len, &data, iint); if (rc == 0) { data.hdr.xattr.sha1.type = EVM_XATTR_HMAC; - rc = __vfs_setxattr_noperm(&init_user_ns, dentry, + rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_EVM, &data.hdr.xattr.data[1], SHA1_DIGEST_SIZE + 1, 0); } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) { - rc = __vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_EVM); + rc = __vfs_removexattr(&nop_mnt_idmap, dentry, XATTR_NAME_EVM); } return rc; } -int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, +int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, char *hmac_val) { struct shash_desc *desc; + const struct xattr *xattr; desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); if (IS_ERR(desc)) { @@ -397,7 +408,13 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, return PTR_ERR(desc); } - crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len); + for (xattr = xattrs; xattr->name; xattr++) { + if (!evm_protected_xattr(xattr->name)) + continue; + + crypto_shash_update(desc, xattr->value, xattr->value_len); + } + hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val); kfree(desc); return 0; |
