162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2005-2010 IBM Corporation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: 662306a36Sopenharmony_ci * Mimi Zohar <zohar@us.ibm.com> 762306a36Sopenharmony_ci * Kylene Hall <kjhall@us.ibm.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * File: evm_main.c 1062306a36Sopenharmony_ci * implements evm_inode_setxattr, evm_inode_post_setxattr, 1162306a36Sopenharmony_ci * evm_inode_removexattr, evm_verifyxattr, and evm_inode_set_acl. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) "EVM: "fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/crypto.h> 1862306a36Sopenharmony_ci#include <linux/audit.h> 1962306a36Sopenharmony_ci#include <linux/xattr.h> 2062306a36Sopenharmony_ci#include <linux/integrity.h> 2162306a36Sopenharmony_ci#include <linux/evm.h> 2262306a36Sopenharmony_ci#include <linux/magic.h> 2362306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 2462306a36Sopenharmony_ci#include <linux/lsm_hooks.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <crypto/hash.h> 2762306a36Sopenharmony_ci#include <crypto/hash_info.h> 2862306a36Sopenharmony_ci#include <crypto/algapi.h> 2962306a36Sopenharmony_ci#include "evm.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint evm_initialized; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const char * const integrity_status_msg[] = { 3462306a36Sopenharmony_ci "pass", "pass_immutable", "fail", "fail_immutable", "no_label", 3562306a36Sopenharmony_ci "no_xattrs", "unknown" 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ciint evm_hmac_attrs; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct xattr_list evm_config_default_xattrnames[] = { 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci .name = XATTR_NAME_SELINUX, 4262306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_SECURITY_SELINUX) 4362306a36Sopenharmony_ci }, 4462306a36Sopenharmony_ci { 4562306a36Sopenharmony_ci .name = XATTR_NAME_SMACK, 4662306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_SECURITY_SMACK) 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci { 4962306a36Sopenharmony_ci .name = XATTR_NAME_SMACKEXEC, 5062306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) 5162306a36Sopenharmony_ci }, 5262306a36Sopenharmony_ci { 5362306a36Sopenharmony_ci .name = XATTR_NAME_SMACKTRANSMUTE, 5462306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) 5562306a36Sopenharmony_ci }, 5662306a36Sopenharmony_ci { 5762306a36Sopenharmony_ci .name = XATTR_NAME_SMACKMMAP, 5862306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) 5962306a36Sopenharmony_ci }, 6062306a36Sopenharmony_ci { 6162306a36Sopenharmony_ci .name = XATTR_NAME_APPARMOR, 6262306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_SECURITY_APPARMOR) 6362306a36Sopenharmony_ci }, 6462306a36Sopenharmony_ci { 6562306a36Sopenharmony_ci .name = XATTR_NAME_IMA, 6662306a36Sopenharmony_ci .enabled = IS_ENABLED(CONFIG_IMA_APPRAISE) 6762306a36Sopenharmony_ci }, 6862306a36Sopenharmony_ci { 6962306a36Sopenharmony_ci .name = XATTR_NAME_CAPS, 7062306a36Sopenharmony_ci .enabled = true 7162306a36Sopenharmony_ci }, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciLIST_HEAD(evm_config_xattrnames); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int evm_fixmode __ro_after_init; 7762306a36Sopenharmony_cistatic int __init evm_set_fixmode(char *str) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (strncmp(str, "fix", 3) == 0) 8062306a36Sopenharmony_ci evm_fixmode = 1; 8162306a36Sopenharmony_ci else 8262306a36Sopenharmony_ci pr_err("invalid \"%s\" mode", str); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 1; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci__setup("evm=", evm_set_fixmode); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void __init evm_init_config(void) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int i, xattrs; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci xattrs = ARRAY_SIZE(evm_config_default_xattrnames); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci pr_info("Initialising EVM extended attributes:\n"); 9562306a36Sopenharmony_ci for (i = 0; i < xattrs; i++) { 9662306a36Sopenharmony_ci pr_info("%s%s\n", evm_config_default_xattrnames[i].name, 9762306a36Sopenharmony_ci !evm_config_default_xattrnames[i].enabled ? 9862306a36Sopenharmony_ci " (disabled)" : ""); 9962306a36Sopenharmony_ci list_add_tail(&evm_config_default_xattrnames[i].list, 10062306a36Sopenharmony_ci &evm_config_xattrnames); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#ifdef CONFIG_EVM_ATTR_FSUUID 10462306a36Sopenharmony_ci evm_hmac_attrs |= EVM_ATTR_FSUUID; 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic bool evm_key_loaded(void) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return (bool)(evm_initialized & EVM_KEY_MASK); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * This function determines whether or not it is safe to ignore verification 11662306a36Sopenharmony_ci * errors, based on the ability of EVM to calculate HMACs. If the HMAC key 11762306a36Sopenharmony_ci * is not loaded, and it cannot be loaded in the future due to the 11862306a36Sopenharmony_ci * EVM_SETUP_COMPLETE initialization flag, allowing an operation despite the 11962306a36Sopenharmony_ci * attrs/xattrs being found invalid will not make them valid. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic bool evm_hmac_disabled(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (evm_initialized & EVM_INIT_HMAC) 12462306a36Sopenharmony_ci return false; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!(evm_initialized & EVM_SETUP_COMPLETE)) 12762306a36Sopenharmony_ci return false; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return true; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int evm_find_protected_xattrs(struct dentry *dentry) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 13562306a36Sopenharmony_ci struct xattr_list *xattr; 13662306a36Sopenharmony_ci int error; 13762306a36Sopenharmony_ci int count = 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!(inode->i_opflags & IOP_XATTR)) 14062306a36Sopenharmony_ci return -EOPNOTSUPP; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) { 14362306a36Sopenharmony_ci error = __vfs_getxattr(dentry, inode, xattr->name, NULL, 0); 14462306a36Sopenharmony_ci if (error < 0) { 14562306a36Sopenharmony_ci if (error == -ENODATA) 14662306a36Sopenharmony_ci continue; 14762306a36Sopenharmony_ci return error; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci count++; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return count; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Compute the HMAC on the dentry's protected set of extended attributes 15962306a36Sopenharmony_ci * and compare it against the stored security.evm xattr. 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * For performance: 16262306a36Sopenharmony_ci * - use the previoulsy retrieved xattr value and length to calculate the 16362306a36Sopenharmony_ci * HMAC.) 16462306a36Sopenharmony_ci * - cache the verification result in the iint, when available. 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * Returns integrity status 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic enum integrity_status evm_verify_hmac(struct dentry *dentry, 16962306a36Sopenharmony_ci const char *xattr_name, 17062306a36Sopenharmony_ci char *xattr_value, 17162306a36Sopenharmony_ci size_t xattr_value_len, 17262306a36Sopenharmony_ci struct integrity_iint_cache *iint) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct evm_ima_xattr_data *xattr_data = NULL; 17562306a36Sopenharmony_ci struct signature_v2_hdr *hdr; 17662306a36Sopenharmony_ci enum integrity_status evm_status = INTEGRITY_PASS; 17762306a36Sopenharmony_ci struct evm_digest digest; 17862306a36Sopenharmony_ci struct inode *inode; 17962306a36Sopenharmony_ci int rc, xattr_len, evm_immutable = 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (iint && (iint->evm_status == INTEGRITY_PASS || 18262306a36Sopenharmony_ci iint->evm_status == INTEGRITY_PASS_IMMUTABLE)) 18362306a36Sopenharmony_ci return iint->evm_status; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* if status is not PASS, try to check again - against -ENOMEM */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* first need to know the sig type */ 18862306a36Sopenharmony_ci rc = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, XATTR_NAME_EVM, 18962306a36Sopenharmony_ci (char **)&xattr_data, 0, GFP_NOFS); 19062306a36Sopenharmony_ci if (rc <= 0) { 19162306a36Sopenharmony_ci evm_status = INTEGRITY_FAIL; 19262306a36Sopenharmony_ci if (rc == -ENODATA) { 19362306a36Sopenharmony_ci rc = evm_find_protected_xattrs(dentry); 19462306a36Sopenharmony_ci if (rc > 0) 19562306a36Sopenharmony_ci evm_status = INTEGRITY_NOLABEL; 19662306a36Sopenharmony_ci else if (rc == 0) 19762306a36Sopenharmony_ci evm_status = INTEGRITY_NOXATTRS; /* new file */ 19862306a36Sopenharmony_ci } else if (rc == -EOPNOTSUPP) { 19962306a36Sopenharmony_ci evm_status = INTEGRITY_UNKNOWN; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci goto out; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci xattr_len = rc; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* check value type */ 20762306a36Sopenharmony_ci switch (xattr_data->type) { 20862306a36Sopenharmony_ci case EVM_XATTR_HMAC: 20962306a36Sopenharmony_ci if (xattr_len != sizeof(struct evm_xattr)) { 21062306a36Sopenharmony_ci evm_status = INTEGRITY_FAIL; 21162306a36Sopenharmony_ci goto out; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci digest.hdr.algo = HASH_ALGO_SHA1; 21562306a36Sopenharmony_ci rc = evm_calc_hmac(dentry, xattr_name, xattr_value, 21662306a36Sopenharmony_ci xattr_value_len, &digest); 21762306a36Sopenharmony_ci if (rc) 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci rc = crypto_memneq(xattr_data->data, digest.digest, 22062306a36Sopenharmony_ci SHA1_DIGEST_SIZE); 22162306a36Sopenharmony_ci if (rc) 22262306a36Sopenharmony_ci rc = -EINVAL; 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case EVM_XATTR_PORTABLE_DIGSIG: 22562306a36Sopenharmony_ci evm_immutable = 1; 22662306a36Sopenharmony_ci fallthrough; 22762306a36Sopenharmony_ci case EVM_IMA_XATTR_DIGSIG: 22862306a36Sopenharmony_ci /* accept xattr with non-empty signature field */ 22962306a36Sopenharmony_ci if (xattr_len <= sizeof(struct signature_v2_hdr)) { 23062306a36Sopenharmony_ci evm_status = INTEGRITY_FAIL; 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci hdr = (struct signature_v2_hdr *)xattr_data; 23562306a36Sopenharmony_ci digest.hdr.algo = hdr->hash_algo; 23662306a36Sopenharmony_ci rc = evm_calc_hash(dentry, xattr_name, xattr_value, 23762306a36Sopenharmony_ci xattr_value_len, xattr_data->type, &digest); 23862306a36Sopenharmony_ci if (rc) 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, 24162306a36Sopenharmony_ci (const char *)xattr_data, xattr_len, 24262306a36Sopenharmony_ci digest.digest, digest.hdr.length); 24362306a36Sopenharmony_ci if (!rc) { 24462306a36Sopenharmony_ci inode = d_backing_inode(dentry); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) { 24762306a36Sopenharmony_ci if (iint) 24862306a36Sopenharmony_ci iint->flags |= EVM_IMMUTABLE_DIGSIG; 24962306a36Sopenharmony_ci evm_status = INTEGRITY_PASS_IMMUTABLE; 25062306a36Sopenharmony_ci } else if (!IS_RDONLY(inode) && 25162306a36Sopenharmony_ci !(inode->i_sb->s_readonly_remount) && 25262306a36Sopenharmony_ci !IS_IMMUTABLE(inode)) { 25362306a36Sopenharmony_ci evm_update_evmxattr(dentry, xattr_name, 25462306a36Sopenharmony_ci xattr_value, 25562306a36Sopenharmony_ci xattr_value_len); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci default: 26062306a36Sopenharmony_ci rc = -EINVAL; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (rc) { 26562306a36Sopenharmony_ci if (rc == -ENODATA) 26662306a36Sopenharmony_ci evm_status = INTEGRITY_NOXATTRS; 26762306a36Sopenharmony_ci else if (evm_immutable) 26862306a36Sopenharmony_ci evm_status = INTEGRITY_FAIL_IMMUTABLE; 26962306a36Sopenharmony_ci else 27062306a36Sopenharmony_ci evm_status = INTEGRITY_FAIL; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci pr_debug("digest: (%d) [%*phN]\n", digest.hdr.length, digest.hdr.length, 27362306a36Sopenharmony_ci digest.digest); 27462306a36Sopenharmony_ciout: 27562306a36Sopenharmony_ci if (iint) 27662306a36Sopenharmony_ci iint->evm_status = evm_status; 27762306a36Sopenharmony_ci kfree(xattr_data); 27862306a36Sopenharmony_ci return evm_status; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int evm_protected_xattr_common(const char *req_xattr_name, 28262306a36Sopenharmony_ci bool all_xattrs) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci int namelen; 28562306a36Sopenharmony_ci int found = 0; 28662306a36Sopenharmony_ci struct xattr_list *xattr; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci namelen = strlen(req_xattr_name); 28962306a36Sopenharmony_ci list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) { 29062306a36Sopenharmony_ci if (!all_xattrs && !xattr->enabled) 29162306a36Sopenharmony_ci continue; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if ((strlen(xattr->name) == namelen) 29462306a36Sopenharmony_ci && (strncmp(req_xattr_name, xattr->name, namelen) == 0)) { 29562306a36Sopenharmony_ci found = 1; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci if (strncmp(req_xattr_name, 29962306a36Sopenharmony_ci xattr->name + XATTR_SECURITY_PREFIX_LEN, 30062306a36Sopenharmony_ci strlen(req_xattr_name)) == 0) { 30162306a36Sopenharmony_ci found = 1; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return found; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciint evm_protected_xattr(const char *req_xattr_name) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci return evm_protected_xattr_common(req_xattr_name, false); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciint evm_protected_xattr_if_enabled(const char *req_xattr_name) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci return evm_protected_xattr_common(req_xattr_name, true); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/** 32062306a36Sopenharmony_ci * evm_read_protected_xattrs - read EVM protected xattr names, lengths, values 32162306a36Sopenharmony_ci * @dentry: dentry of the read xattrs 32262306a36Sopenharmony_ci * @buffer: buffer xattr names, lengths or values are copied to 32362306a36Sopenharmony_ci * @buffer_size: size of buffer 32462306a36Sopenharmony_ci * @type: n: names, l: lengths, v: values 32562306a36Sopenharmony_ci * @canonical_fmt: data format (true: little endian, false: native format) 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * Read protected xattr names (separated by |), lengths (u32) or values for a 32862306a36Sopenharmony_ci * given dentry and return the total size of copied data. If buffer is NULL, 32962306a36Sopenharmony_ci * just return the total size. 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * Returns the total size on success, a negative value on error. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_ciint evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, 33462306a36Sopenharmony_ci int buffer_size, char type, bool canonical_fmt) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct xattr_list *xattr; 33762306a36Sopenharmony_ci int rc, size, total_size = 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) { 34062306a36Sopenharmony_ci rc = __vfs_getxattr(dentry, d_backing_inode(dentry), 34162306a36Sopenharmony_ci xattr->name, NULL, 0); 34262306a36Sopenharmony_ci if (rc < 0 && rc == -ENODATA) 34362306a36Sopenharmony_ci continue; 34462306a36Sopenharmony_ci else if (rc < 0) 34562306a36Sopenharmony_ci return rc; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci switch (type) { 34862306a36Sopenharmony_ci case 'n': 34962306a36Sopenharmony_ci size = strlen(xattr->name) + 1; 35062306a36Sopenharmony_ci if (buffer) { 35162306a36Sopenharmony_ci if (total_size) 35262306a36Sopenharmony_ci *(buffer + total_size - 1) = '|'; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci memcpy(buffer + total_size, xattr->name, size); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case 'l': 35862306a36Sopenharmony_ci size = sizeof(u32); 35962306a36Sopenharmony_ci if (buffer) { 36062306a36Sopenharmony_ci if (canonical_fmt) 36162306a36Sopenharmony_ci rc = (__force int)cpu_to_le32(rc); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci *(u32 *)(buffer + total_size) = rc; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci case 'v': 36762306a36Sopenharmony_ci size = rc; 36862306a36Sopenharmony_ci if (buffer) { 36962306a36Sopenharmony_ci rc = __vfs_getxattr(dentry, 37062306a36Sopenharmony_ci d_backing_inode(dentry), xattr->name, 37162306a36Sopenharmony_ci buffer + total_size, 37262306a36Sopenharmony_ci buffer_size - total_size); 37362306a36Sopenharmony_ci if (rc < 0) 37462306a36Sopenharmony_ci return rc; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci default: 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci total_size += size; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return total_size; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * evm_verifyxattr - verify the integrity of the requested xattr 38962306a36Sopenharmony_ci * @dentry: object of the verify xattr 39062306a36Sopenharmony_ci * @xattr_name: requested xattr 39162306a36Sopenharmony_ci * @xattr_value: requested xattr value 39262306a36Sopenharmony_ci * @xattr_value_len: requested xattr value length 39362306a36Sopenharmony_ci * @iint: inode integrity metadata 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * Calculate the HMAC for the given dentry and verify it against the stored 39662306a36Sopenharmony_ci * security.evm xattr. For performance, use the xattr value and length 39762306a36Sopenharmony_ci * previously retrieved to calculate the HMAC. 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Returns the xattr integrity status. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * This function requires the caller to lock the inode's i_mutex before it 40262306a36Sopenharmony_ci * is executed. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_cienum integrity_status evm_verifyxattr(struct dentry *dentry, 40562306a36Sopenharmony_ci const char *xattr_name, 40662306a36Sopenharmony_ci void *xattr_value, size_t xattr_value_len, 40762306a36Sopenharmony_ci struct integrity_iint_cache *iint) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci if (!evm_key_loaded() || !evm_protected_xattr(xattr_name)) 41062306a36Sopenharmony_ci return INTEGRITY_UNKNOWN; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!iint) { 41362306a36Sopenharmony_ci iint = integrity_iint_find(d_backing_inode(dentry)); 41462306a36Sopenharmony_ci if (!iint) 41562306a36Sopenharmony_ci return INTEGRITY_UNKNOWN; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci return evm_verify_hmac(dentry, xattr_name, xattr_value, 41862306a36Sopenharmony_ci xattr_value_len, iint); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(evm_verifyxattr); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* 42362306a36Sopenharmony_ci * evm_verify_current_integrity - verify the dentry's metadata integrity 42462306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * Verify and return the dentry's metadata integrity. The exceptions are 42762306a36Sopenharmony_ci * before EVM is initialized or in 'fix' mode. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic enum integrity_status evm_verify_current_integrity(struct dentry *dentry) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode) 43462306a36Sopenharmony_ci return INTEGRITY_PASS; 43562306a36Sopenharmony_ci return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* 43962306a36Sopenharmony_ci * evm_xattr_change - check if passed xattr value differs from current value 44062306a36Sopenharmony_ci * @idmap: idmap of the mount 44162306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 44262306a36Sopenharmony_ci * @xattr_name: requested xattr 44362306a36Sopenharmony_ci * @xattr_value: requested xattr value 44462306a36Sopenharmony_ci * @xattr_value_len: requested xattr value length 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * Check if passed xattr value differs from current value. 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * Returns 1 if passed xattr value differs from current value, 0 otherwise. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_cistatic int evm_xattr_change(struct mnt_idmap *idmap, 45162306a36Sopenharmony_ci struct dentry *dentry, const char *xattr_name, 45262306a36Sopenharmony_ci const void *xattr_value, size_t xattr_value_len) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci char *xattr_data = NULL; 45562306a36Sopenharmony_ci int rc = 0; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci rc = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, xattr_name, &xattr_data, 45862306a36Sopenharmony_ci 0, GFP_NOFS); 45962306a36Sopenharmony_ci if (rc < 0) { 46062306a36Sopenharmony_ci rc = 1; 46162306a36Sopenharmony_ci goto out; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (rc == xattr_value_len) 46562306a36Sopenharmony_ci rc = !!memcmp(xattr_value, xattr_data, rc); 46662306a36Sopenharmony_ci else 46762306a36Sopenharmony_ci rc = 1; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciout: 47062306a36Sopenharmony_ci kfree(xattr_data); 47162306a36Sopenharmony_ci return rc; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * evm_protect_xattr - protect the EVM extended attribute 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * Prevent security.evm from being modified or removed without the 47862306a36Sopenharmony_ci * necessary permissions or when the existing value is invalid. 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * The posix xattr acls are 'system' prefixed, which normally would not 48162306a36Sopenharmony_ci * affect security.evm. An interesting side affect of writing posix xattr 48262306a36Sopenharmony_ci * acls is their modifying of the i_mode, which is included in security.evm. 48362306a36Sopenharmony_ci * For posix xattr acls only, permit security.evm, even if it currently 48462306a36Sopenharmony_ci * doesn't exist, to be updated unless the EVM signature is immutable. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_cistatic int evm_protect_xattr(struct mnt_idmap *idmap, 48762306a36Sopenharmony_ci struct dentry *dentry, const char *xattr_name, 48862306a36Sopenharmony_ci const void *xattr_value, size_t xattr_value_len) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci enum integrity_status evm_status; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 49362306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 49462306a36Sopenharmony_ci return -EPERM; 49562306a36Sopenharmony_ci } else if (!evm_protected_xattr(xattr_name)) { 49662306a36Sopenharmony_ci if (!posix_xattr_acl(xattr_name)) 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci evm_status = evm_verify_current_integrity(dentry); 49962306a36Sopenharmony_ci if ((evm_status == INTEGRITY_PASS) || 50062306a36Sopenharmony_ci (evm_status == INTEGRITY_NOXATTRS)) 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci goto out; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci evm_status = evm_verify_current_integrity(dentry); 50662306a36Sopenharmony_ci if (evm_status == INTEGRITY_NOXATTRS) { 50762306a36Sopenharmony_ci struct integrity_iint_cache *iint; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Exception if the HMAC is not going to be calculated. */ 51062306a36Sopenharmony_ci if (evm_hmac_disabled()) 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci iint = integrity_iint_find(d_backing_inode(dentry)); 51462306a36Sopenharmony_ci if (iint && (iint->flags & IMA_NEW_FILE)) 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* exception for pseudo filesystems */ 51862306a36Sopenharmony_ci if (dentry->d_sb->s_magic == TMPFS_MAGIC 51962306a36Sopenharmony_ci || dentry->d_sb->s_magic == SYSFS_MAGIC) 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_METADATA, 52362306a36Sopenharmony_ci dentry->d_inode, dentry->d_name.name, 52462306a36Sopenharmony_ci "update_metadata", 52562306a36Sopenharmony_ci integrity_status_msg[evm_status], 52662306a36Sopenharmony_ci -EPERM, 0); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ciout: 52962306a36Sopenharmony_ci /* Exception if the HMAC is not going to be calculated. */ 53062306a36Sopenharmony_ci if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL || 53162306a36Sopenharmony_ci evm_status == INTEGRITY_UNKNOWN)) 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * Writing other xattrs is safe for portable signatures, as portable 53662306a36Sopenharmony_ci * signatures are immutable and can never be updated. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci if (evm_status == INTEGRITY_FAIL_IMMUTABLE) 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (evm_status == INTEGRITY_PASS_IMMUTABLE && 54262306a36Sopenharmony_ci !evm_xattr_change(idmap, dentry, xattr_name, xattr_value, 54362306a36Sopenharmony_ci xattr_value_len)) 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (evm_status != INTEGRITY_PASS && 54762306a36Sopenharmony_ci evm_status != INTEGRITY_PASS_IMMUTABLE) 54862306a36Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 54962306a36Sopenharmony_ci dentry->d_name.name, "appraise_metadata", 55062306a36Sopenharmony_ci integrity_status_msg[evm_status], 55162306a36Sopenharmony_ci -EPERM, 0); 55262306a36Sopenharmony_ci return evm_status == INTEGRITY_PASS ? 0 : -EPERM; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/** 55662306a36Sopenharmony_ci * evm_inode_setxattr - protect the EVM extended attribute 55762306a36Sopenharmony_ci * @idmap: idmap of the mount 55862306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 55962306a36Sopenharmony_ci * @xattr_name: pointer to the affected extended attribute name 56062306a36Sopenharmony_ci * @xattr_value: pointer to the new extended attribute value 56162306a36Sopenharmony_ci * @xattr_value_len: pointer to the new extended attribute value length 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * Before allowing the 'security.evm' protected xattr to be updated, 56462306a36Sopenharmony_ci * verify the existing value is valid. As only the kernel should have 56562306a36Sopenharmony_ci * access to the EVM encrypted key needed to calculate the HMAC, prevent 56662306a36Sopenharmony_ci * userspace from writing HMAC value. Writing 'security.evm' requires 56762306a36Sopenharmony_ci * requires CAP_SYS_ADMIN privileges. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ciint evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, 57062306a36Sopenharmony_ci const char *xattr_name, const void *xattr_value, 57162306a36Sopenharmony_ci size_t xattr_value_len) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci const struct evm_ima_xattr_data *xattr_data = xattr_value; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Policy permits modification of the protected xattrs even though 57662306a36Sopenharmony_ci * there's no HMAC key loaded 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci if (evm_initialized & EVM_ALLOW_METADATA_WRITES) 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 58262306a36Sopenharmony_ci if (!xattr_value_len) 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && 58562306a36Sopenharmony_ci xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) 58662306a36Sopenharmony_ci return -EPERM; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci return evm_protect_xattr(idmap, dentry, xattr_name, xattr_value, 58962306a36Sopenharmony_ci xattr_value_len); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/** 59362306a36Sopenharmony_ci * evm_inode_removexattr - protect the EVM extended attribute 59462306a36Sopenharmony_ci * @idmap: idmap of the mount 59562306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 59662306a36Sopenharmony_ci * @xattr_name: pointer to the affected extended attribute name 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that 59962306a36Sopenharmony_ci * the current value is valid. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ciint evm_inode_removexattr(struct mnt_idmap *idmap, 60262306a36Sopenharmony_ci struct dentry *dentry, const char *xattr_name) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci /* Policy permits modification of the protected xattrs even though 60562306a36Sopenharmony_ci * there's no HMAC key loaded 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ci if (evm_initialized & EVM_ALLOW_METADATA_WRITES) 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return evm_protect_xattr(idmap, dentry, xattr_name, NULL, 0); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci#ifdef CONFIG_FS_POSIX_ACL 61462306a36Sopenharmony_cistatic int evm_inode_set_acl_change(struct mnt_idmap *idmap, 61562306a36Sopenharmony_ci struct dentry *dentry, const char *name, 61662306a36Sopenharmony_ci struct posix_acl *kacl) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci int rc; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci umode_t mode; 62162306a36Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!kacl) 62462306a36Sopenharmony_ci return 1; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci rc = posix_acl_update_mode(idmap, inode, &mode, &kacl); 62762306a36Sopenharmony_ci if (rc || (inode->i_mode != mode)) 62862306a36Sopenharmony_ci return 1; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci#else 63362306a36Sopenharmony_cistatic inline int evm_inode_set_acl_change(struct mnt_idmap *idmap, 63462306a36Sopenharmony_ci struct dentry *dentry, 63562306a36Sopenharmony_ci const char *name, 63662306a36Sopenharmony_ci struct posix_acl *kacl) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci/** 64362306a36Sopenharmony_ci * evm_inode_set_acl - protect the EVM extended attribute from posix acls 64462306a36Sopenharmony_ci * @idmap: idmap of the idmapped mount 64562306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 64662306a36Sopenharmony_ci * @acl_name: name of the posix acl 64762306a36Sopenharmony_ci * @kacl: pointer to the posix acls 64862306a36Sopenharmony_ci * 64962306a36Sopenharmony_ci * Prevent modifying posix acls causing the EVM HMAC to be re-calculated 65062306a36Sopenharmony_ci * and 'security.evm' xattr updated, unless the existing 'security.evm' is 65162306a36Sopenharmony_ci * valid. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ciint evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 65462306a36Sopenharmony_ci const char *acl_name, struct posix_acl *kacl) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci enum integrity_status evm_status; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Policy permits modification of the protected xattrs even though 65962306a36Sopenharmony_ci * there's no HMAC key loaded 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci if (evm_initialized & EVM_ALLOW_METADATA_WRITES) 66262306a36Sopenharmony_ci return 0; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci evm_status = evm_verify_current_integrity(dentry); 66562306a36Sopenharmony_ci if ((evm_status == INTEGRITY_PASS) || 66662306a36Sopenharmony_ci (evm_status == INTEGRITY_NOXATTRS)) 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Exception if the HMAC is not going to be calculated. */ 67062306a36Sopenharmony_ci if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL || 67162306a36Sopenharmony_ci evm_status == INTEGRITY_UNKNOWN)) 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Writing other xattrs is safe for portable signatures, as portable 67662306a36Sopenharmony_ci * signatures are immutable and can never be updated. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci if (evm_status == INTEGRITY_FAIL_IMMUTABLE) 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (evm_status == INTEGRITY_PASS_IMMUTABLE && 68262306a36Sopenharmony_ci !evm_inode_set_acl_change(idmap, dentry, acl_name, kacl)) 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (evm_status != INTEGRITY_PASS_IMMUTABLE) 68662306a36Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 68762306a36Sopenharmony_ci dentry->d_name.name, "appraise_metadata", 68862306a36Sopenharmony_ci integrity_status_msg[evm_status], 68962306a36Sopenharmony_ci -EPERM, 0); 69062306a36Sopenharmony_ci return -EPERM; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic void evm_reset_status(struct inode *inode) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct integrity_iint_cache *iint; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci iint = integrity_iint_find(inode); 69862306a36Sopenharmony_ci if (iint) 69962306a36Sopenharmony_ci iint->evm_status = INTEGRITY_UNKNOWN; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci/** 70362306a36Sopenharmony_ci * evm_revalidate_status - report whether EVM status re-validation is necessary 70462306a36Sopenharmony_ci * @xattr_name: pointer to the affected extended attribute name 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci * Report whether callers of evm_verifyxattr() should re-validate the 70762306a36Sopenharmony_ci * EVM status. 70862306a36Sopenharmony_ci * 70962306a36Sopenharmony_ci * Return true if re-validation is necessary, false otherwise. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_cibool evm_revalidate_status(const char *xattr_name) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci if (!evm_key_loaded()) 71462306a36Sopenharmony_ci return false; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* evm_inode_post_setattr() passes NULL */ 71762306a36Sopenharmony_ci if (!xattr_name) 71862306a36Sopenharmony_ci return true; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!evm_protected_xattr(xattr_name) && !posix_xattr_acl(xattr_name) && 72162306a36Sopenharmony_ci strcmp(xattr_name, XATTR_NAME_EVM)) 72262306a36Sopenharmony_ci return false; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return true; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/** 72862306a36Sopenharmony_ci * evm_inode_post_setxattr - update 'security.evm' to reflect the changes 72962306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 73062306a36Sopenharmony_ci * @xattr_name: pointer to the affected extended attribute name 73162306a36Sopenharmony_ci * @xattr_value: pointer to the new extended attribute value 73262306a36Sopenharmony_ci * @xattr_value_len: pointer to the new extended attribute value length 73362306a36Sopenharmony_ci * 73462306a36Sopenharmony_ci * Update the HMAC stored in 'security.evm' to reflect the change. 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * No need to take the i_mutex lock here, as this function is called from 73762306a36Sopenharmony_ci * __vfs_setxattr_noperm(). The caller of which has taken the inode's 73862306a36Sopenharmony_ci * i_mutex lock. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_civoid evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, 74162306a36Sopenharmony_ci const void *xattr_value, size_t xattr_value_len) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci if (!evm_revalidate_status(xattr_name)) 74462306a36Sopenharmony_ci return; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci evm_reset_status(dentry->d_inode); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!strcmp(xattr_name, XATTR_NAME_EVM)) 74962306a36Sopenharmony_ci return; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (!(evm_initialized & EVM_INIT_HMAC)) 75262306a36Sopenharmony_ci return; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/** 75862306a36Sopenharmony_ci * evm_inode_post_removexattr - update 'security.evm' after removing the xattr 75962306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 76062306a36Sopenharmony_ci * @xattr_name: pointer to the affected extended attribute name 76162306a36Sopenharmony_ci * 76262306a36Sopenharmony_ci * Update the HMAC stored in 'security.evm' to reflect removal of the xattr. 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * No need to take the i_mutex lock here, as this function is called from 76562306a36Sopenharmony_ci * vfs_removexattr() which takes the i_mutex. 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_civoid evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci if (!evm_revalidate_status(xattr_name)) 77062306a36Sopenharmony_ci return; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci evm_reset_status(dentry->d_inode); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (!strcmp(xattr_name, XATTR_NAME_EVM)) 77562306a36Sopenharmony_ci return; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (!(evm_initialized & EVM_INIT_HMAC)) 77862306a36Sopenharmony_ci return; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci evm_update_evmxattr(dentry, xattr_name, NULL, 0); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int evm_attr_change(struct mnt_idmap *idmap, 78462306a36Sopenharmony_ci struct dentry *dentry, struct iattr *attr) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 78762306a36Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (!i_uid_needs_update(idmap, attr, inode) && 79062306a36Sopenharmony_ci !i_gid_needs_update(idmap, attr, inode) && 79162306a36Sopenharmony_ci (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode)) 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return 1; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/** 79862306a36Sopenharmony_ci * evm_inode_setattr - prevent updating an invalid EVM extended attribute 79962306a36Sopenharmony_ci * @idmap: idmap of the mount 80062306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 80162306a36Sopenharmony_ci * @attr: iattr structure containing the new file attributes 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * Permit update of file attributes when files have a valid EVM signature, 80462306a36Sopenharmony_ci * except in the case of them having an immutable portable signature. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ciint evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 80762306a36Sopenharmony_ci struct iattr *attr) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 81062306a36Sopenharmony_ci enum integrity_status evm_status; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* Policy permits modification of the protected attrs even though 81362306a36Sopenharmony_ci * there's no HMAC key loaded 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci if (evm_initialized & EVM_ALLOW_METADATA_WRITES) 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci evm_status = evm_verify_current_integrity(dentry); 82162306a36Sopenharmony_ci /* 82262306a36Sopenharmony_ci * Writing attrs is safe for portable signatures, as portable signatures 82362306a36Sopenharmony_ci * are immutable and can never be updated. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci if ((evm_status == INTEGRITY_PASS) || 82662306a36Sopenharmony_ci (evm_status == INTEGRITY_NOXATTRS) || 82762306a36Sopenharmony_ci (evm_status == INTEGRITY_FAIL_IMMUTABLE) || 82862306a36Sopenharmony_ci (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL || 82962306a36Sopenharmony_ci evm_status == INTEGRITY_UNKNOWN))) 83062306a36Sopenharmony_ci return 0; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (evm_status == INTEGRITY_PASS_IMMUTABLE && 83362306a36Sopenharmony_ci !evm_attr_change(idmap, dentry, attr)) 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 83762306a36Sopenharmony_ci dentry->d_name.name, "appraise_metadata", 83862306a36Sopenharmony_ci integrity_status_msg[evm_status], -EPERM, 0); 83962306a36Sopenharmony_ci return -EPERM; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/** 84362306a36Sopenharmony_ci * evm_inode_post_setattr - update 'security.evm' after modifying metadata 84462306a36Sopenharmony_ci * @dentry: pointer to the affected dentry 84562306a36Sopenharmony_ci * @ia_valid: for the UID and GID status 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * For now, update the HMAC stored in 'security.evm' to reflect UID/GID 84862306a36Sopenharmony_ci * changes. 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * This function is called from notify_change(), which expects the caller 85162306a36Sopenharmony_ci * to lock the inode's i_mutex. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_civoid evm_inode_post_setattr(struct dentry *dentry, int ia_valid) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci if (!evm_revalidate_status(NULL)) 85662306a36Sopenharmony_ci return; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci evm_reset_status(dentry->d_inode); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (!(evm_initialized & EVM_INIT_HMAC)) 86162306a36Sopenharmony_ci return; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) 86462306a36Sopenharmony_ci evm_update_evmxattr(dentry, NULL, NULL, 0); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci/* 86862306a36Sopenharmony_ci * evm_inode_init_security - initializes security.evm HMAC value 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ciint evm_inode_init_security(struct inode *inode, struct inode *dir, 87162306a36Sopenharmony_ci const struct qstr *qstr, struct xattr *xattrs, 87262306a36Sopenharmony_ci int *xattr_count) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct evm_xattr *xattr_data; 87562306a36Sopenharmony_ci struct xattr *xattr, *evm_xattr; 87662306a36Sopenharmony_ci bool evm_protected_xattrs = false; 87762306a36Sopenharmony_ci int rc; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs) 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* 88362306a36Sopenharmony_ci * security_inode_init_security() makes sure that the xattrs array is 88462306a36Sopenharmony_ci * contiguous, there is enough space for security.evm, and that there is 88562306a36Sopenharmony_ci * a terminator at the end of the array. 88662306a36Sopenharmony_ci */ 88762306a36Sopenharmony_ci for (xattr = xattrs; xattr->name; xattr++) { 88862306a36Sopenharmony_ci if (evm_protected_xattr(xattr->name)) 88962306a36Sopenharmony_ci evm_protected_xattrs = true; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci /* EVM xattr not needed. */ 89362306a36Sopenharmony_ci if (!evm_protected_xattrs) 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci evm_xattr = lsm_get_xattr_slot(xattrs, xattr_count); 89762306a36Sopenharmony_ci /* 89862306a36Sopenharmony_ci * Array terminator (xattr name = NULL) must be the first non-filled 89962306a36Sopenharmony_ci * xattr slot. 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci WARN_ONCE(evm_xattr != xattr, 90262306a36Sopenharmony_ci "%s: xattrs terminator is not the first non-filled slot\n", 90362306a36Sopenharmony_ci __func__); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS); 90662306a36Sopenharmony_ci if (!xattr_data) 90762306a36Sopenharmony_ci return -ENOMEM; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci xattr_data->data.type = EVM_XATTR_HMAC; 91062306a36Sopenharmony_ci rc = evm_init_hmac(inode, xattrs, xattr_data->digest); 91162306a36Sopenharmony_ci if (rc < 0) 91262306a36Sopenharmony_ci goto out; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci evm_xattr->value = xattr_data; 91562306a36Sopenharmony_ci evm_xattr->value_len = sizeof(*xattr_data); 91662306a36Sopenharmony_ci evm_xattr->name = XATTR_EVM_SUFFIX; 91762306a36Sopenharmony_ci return 0; 91862306a36Sopenharmony_ciout: 91962306a36Sopenharmony_ci kfree(xattr_data); 92062306a36Sopenharmony_ci return rc; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(evm_inode_init_security); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci#ifdef CONFIG_EVM_LOAD_X509 92562306a36Sopenharmony_civoid __init evm_load_x509(void) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci int rc; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH); 93062306a36Sopenharmony_ci if (!rc) 93162306a36Sopenharmony_ci evm_initialized |= EVM_INIT_X509; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci#endif 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic int __init init_evm(void) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci int error; 93862306a36Sopenharmony_ci struct list_head *pos, *q; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci evm_init_config(); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci error = integrity_init_keyring(INTEGRITY_KEYRING_EVM); 94362306a36Sopenharmony_ci if (error) 94462306a36Sopenharmony_ci goto error; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci error = evm_init_secfs(); 94762306a36Sopenharmony_ci if (error < 0) { 94862306a36Sopenharmony_ci pr_info("Error registering secfs\n"); 94962306a36Sopenharmony_ci goto error; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cierror: 95362306a36Sopenharmony_ci if (error != 0) { 95462306a36Sopenharmony_ci if (!list_empty(&evm_config_xattrnames)) { 95562306a36Sopenharmony_ci list_for_each_safe(pos, q, &evm_config_xattrnames) 95662306a36Sopenharmony_ci list_del(pos); 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci return error; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cilate_initcall(init_evm); 964