166dbc325SMimi Zohar /* 266dbc325SMimi Zohar * Copyright (C) 2005-2010 IBM Corporation 366dbc325SMimi Zohar * 466dbc325SMimi Zohar * Author: 566dbc325SMimi Zohar * Mimi Zohar <zohar@us.ibm.com> 666dbc325SMimi Zohar * Kylene Hall <kjhall@us.ibm.com> 766dbc325SMimi Zohar * 866dbc325SMimi Zohar * This program is free software; you can redistribute it and/or modify 966dbc325SMimi Zohar * it under the terms of the GNU General Public License as published by 1066dbc325SMimi Zohar * the Free Software Foundation, version 2 of the License. 1166dbc325SMimi Zohar * 1266dbc325SMimi Zohar * File: evm_main.c 1366dbc325SMimi Zohar * implements evm_inode_setxattr, evm_inode_post_setxattr, 1466dbc325SMimi Zohar * evm_inode_removexattr, and evm_verifyxattr 1566dbc325SMimi Zohar */ 1666dbc325SMimi Zohar 1720ee451fSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1820ee451fSJoe Perches 1966dbc325SMimi Zohar #include <linux/module.h> 2066dbc325SMimi Zohar #include <linux/crypto.h> 219b97b6cdSMimi Zohar #include <linux/audit.h> 2266dbc325SMimi Zohar #include <linux/xattr.h> 2366dbc325SMimi Zohar #include <linux/integrity.h> 243e1be52dSMimi Zohar #include <linux/evm.h> 25d46eb369SDmitry Kasatkin #include <crypto/hash.h> 26613317bdSRyan Ware #include <crypto/algapi.h> 2766dbc325SMimi Zohar #include "evm.h" 2866dbc325SMimi Zohar 2966dbc325SMimi Zohar int evm_initialized; 3066dbc325SMimi Zohar 319b97b6cdSMimi Zohar static char *integrity_status_msg[] = { 329b97b6cdSMimi Zohar "pass", "fail", "no_label", "no_xattrs", "unknown" 339b97b6cdSMimi Zohar }; 3466dbc325SMimi Zohar char *evm_hmac = "hmac(sha1)"; 3515647eb3SDmitry Kasatkin char *evm_hash = "sha1"; 36d3b33679SDmitry Kasatkin int evm_hmac_attrs; 3766dbc325SMimi Zohar 3866dbc325SMimi Zohar char *evm_config_xattrnames[] = { 3966dbc325SMimi Zohar #ifdef CONFIG_SECURITY_SELINUX 4066dbc325SMimi Zohar XATTR_NAME_SELINUX, 4166dbc325SMimi Zohar #endif 4266dbc325SMimi Zohar #ifdef CONFIG_SECURITY_SMACK 4366dbc325SMimi Zohar XATTR_NAME_SMACK, 443e38df56SDmitry Kasatkin #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS 453e38df56SDmitry Kasatkin XATTR_NAME_SMACKEXEC, 463e38df56SDmitry Kasatkin XATTR_NAME_SMACKTRANSMUTE, 473e38df56SDmitry Kasatkin XATTR_NAME_SMACKMMAP, 483e38df56SDmitry Kasatkin #endif 4966dbc325SMimi Zohar #endif 502fe5d6deSMimi Zohar #ifdef CONFIG_IMA_APPRAISE 512fe5d6deSMimi Zohar XATTR_NAME_IMA, 522fe5d6deSMimi Zohar #endif 5366dbc325SMimi Zohar XATTR_NAME_CAPS, 5466dbc325SMimi Zohar NULL 5566dbc325SMimi Zohar }; 5666dbc325SMimi Zohar 577102ebcdSMimi Zohar static int evm_fixmode; 587102ebcdSMimi Zohar static int __init evm_set_fixmode(char *str) 597102ebcdSMimi Zohar { 607102ebcdSMimi Zohar if (strncmp(str, "fix", 3) == 0) 617102ebcdSMimi Zohar evm_fixmode = 1; 627102ebcdSMimi Zohar return 0; 637102ebcdSMimi Zohar } 647102ebcdSMimi Zohar __setup("evm=", evm_set_fixmode); 657102ebcdSMimi Zohar 66d3b33679SDmitry Kasatkin static void __init evm_init_config(void) 67d3b33679SDmitry Kasatkin { 68d3b33679SDmitry Kasatkin #ifdef CONFIG_EVM_ATTR_FSUUID 69d3b33679SDmitry Kasatkin evm_hmac_attrs |= EVM_ATTR_FSUUID; 70d3b33679SDmitry Kasatkin #endif 71d3b33679SDmitry Kasatkin pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); 72d3b33679SDmitry Kasatkin } 73d3b33679SDmitry Kasatkin 7415647eb3SDmitry Kasatkin static int evm_find_protected_xattrs(struct dentry *dentry) 7515647eb3SDmitry Kasatkin { 76c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 7715647eb3SDmitry Kasatkin char **xattr; 7815647eb3SDmitry Kasatkin int error; 7915647eb3SDmitry Kasatkin int count = 0; 8015647eb3SDmitry Kasatkin 81627bf81aSAl Viro if (!inode->i_op->getxattr) 8215647eb3SDmitry Kasatkin return -EOPNOTSUPP; 8315647eb3SDmitry Kasatkin 8415647eb3SDmitry Kasatkin for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { 8515647eb3SDmitry Kasatkin error = inode->i_op->getxattr(dentry, *xattr, NULL, 0); 8615647eb3SDmitry Kasatkin if (error < 0) { 8715647eb3SDmitry Kasatkin if (error == -ENODATA) 8815647eb3SDmitry Kasatkin continue; 8915647eb3SDmitry Kasatkin return error; 9015647eb3SDmitry Kasatkin } 9115647eb3SDmitry Kasatkin count++; 9215647eb3SDmitry Kasatkin } 9315647eb3SDmitry Kasatkin 9415647eb3SDmitry Kasatkin return count; 9515647eb3SDmitry Kasatkin } 9615647eb3SDmitry Kasatkin 9766dbc325SMimi Zohar /* 9866dbc325SMimi Zohar * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr 9966dbc325SMimi Zohar * 10066dbc325SMimi Zohar * Compute the HMAC on the dentry's protected set of extended attributes 1017102ebcdSMimi Zohar * and compare it against the stored security.evm xattr. 1027102ebcdSMimi Zohar * 1037102ebcdSMimi Zohar * For performance: 1047102ebcdSMimi Zohar * - use the previoulsy retrieved xattr value and length to calculate the 10566dbc325SMimi Zohar * HMAC.) 1067102ebcdSMimi Zohar * - cache the verification result in the iint, when available. 10766dbc325SMimi Zohar * 10866dbc325SMimi Zohar * Returns integrity status 10966dbc325SMimi Zohar */ 11066dbc325SMimi Zohar static enum integrity_status evm_verify_hmac(struct dentry *dentry, 11166dbc325SMimi Zohar const char *xattr_name, 11266dbc325SMimi Zohar char *xattr_value, 11366dbc325SMimi Zohar size_t xattr_value_len, 11466dbc325SMimi Zohar struct integrity_iint_cache *iint) 11566dbc325SMimi Zohar { 11615647eb3SDmitry Kasatkin struct evm_ima_xattr_data *xattr_data = NULL; 11715647eb3SDmitry Kasatkin struct evm_ima_xattr_data calc; 118566be59aSMimi Zohar enum integrity_status evm_status = INTEGRITY_PASS; 11915647eb3SDmitry Kasatkin int rc, xattr_len; 12066dbc325SMimi Zohar 1217102ebcdSMimi Zohar if (iint && iint->evm_status == INTEGRITY_PASS) 12224e0198eSDmitry Kasatkin return iint->evm_status; 12366dbc325SMimi Zohar 1246d38ca01SDmitry Kasatkin /* if status is not PASS, try to check again - against -ENOMEM */ 1256d38ca01SDmitry Kasatkin 12615647eb3SDmitry Kasatkin /* first need to know the sig type */ 12715647eb3SDmitry Kasatkin rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0, 12815647eb3SDmitry Kasatkin GFP_NOFS); 12915647eb3SDmitry Kasatkin if (rc <= 0) { 1301f100979SDmitry Kasatkin evm_status = INTEGRITY_FAIL; 1311f100979SDmitry Kasatkin if (rc == -ENODATA) { 13215647eb3SDmitry Kasatkin rc = evm_find_protected_xattrs(dentry); 13315647eb3SDmitry Kasatkin if (rc > 0) 13415647eb3SDmitry Kasatkin evm_status = INTEGRITY_NOLABEL; 13515647eb3SDmitry Kasatkin else if (rc == 0) 13615647eb3SDmitry Kasatkin evm_status = INTEGRITY_NOXATTRS; /* new file */ 1371f100979SDmitry Kasatkin } else if (rc == -EOPNOTSUPP) { 1381f100979SDmitry Kasatkin evm_status = INTEGRITY_UNKNOWN; 13915647eb3SDmitry Kasatkin } 140566be59aSMimi Zohar goto out; 141566be59aSMimi Zohar } 14266dbc325SMimi Zohar 143b1aaab22SDmitry Kasatkin xattr_len = rc; 14415647eb3SDmitry Kasatkin 14515647eb3SDmitry Kasatkin /* check value type */ 14615647eb3SDmitry Kasatkin switch (xattr_data->type) { 14715647eb3SDmitry Kasatkin case EVM_XATTR_HMAC: 14815647eb3SDmitry Kasatkin rc = evm_calc_hmac(dentry, xattr_name, xattr_value, 14915647eb3SDmitry Kasatkin xattr_value_len, calc.digest); 15015647eb3SDmitry Kasatkin if (rc) 15115647eb3SDmitry Kasatkin break; 152613317bdSRyan Ware rc = crypto_memneq(xattr_data->digest, calc.digest, 15315647eb3SDmitry Kasatkin sizeof(calc.digest)); 15415647eb3SDmitry Kasatkin if (rc) 15515647eb3SDmitry Kasatkin rc = -EINVAL; 15615647eb3SDmitry Kasatkin break; 15715647eb3SDmitry Kasatkin case EVM_IMA_XATTR_DIGSIG: 15815647eb3SDmitry Kasatkin rc = evm_calc_hash(dentry, xattr_name, xattr_value, 15915647eb3SDmitry Kasatkin xattr_value_len, calc.digest); 16015647eb3SDmitry Kasatkin if (rc) 16115647eb3SDmitry Kasatkin break; 16215647eb3SDmitry Kasatkin rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, 163b1aaab22SDmitry Kasatkin (const char *)xattr_data, xattr_len, 16415647eb3SDmitry Kasatkin calc.digest, sizeof(calc.digest)); 16515647eb3SDmitry Kasatkin if (!rc) { 166c2baec7fSDmitry Kasatkin /* Replace RSA with HMAC if not mounted readonly and 167c2baec7fSDmitry Kasatkin * not immutable 168c2baec7fSDmitry Kasatkin */ 169c6f493d6SDavid Howells if (!IS_RDONLY(d_backing_inode(dentry)) && 170c6f493d6SDavid Howells !IS_IMMUTABLE(d_backing_inode(dentry))) 171c2baec7fSDmitry Kasatkin evm_update_evmxattr(dentry, xattr_name, 172c2baec7fSDmitry Kasatkin xattr_value, 17315647eb3SDmitry Kasatkin xattr_value_len); 17415647eb3SDmitry Kasatkin } 17515647eb3SDmitry Kasatkin break; 17615647eb3SDmitry Kasatkin default: 17715647eb3SDmitry Kasatkin rc = -EINVAL; 17815647eb3SDmitry Kasatkin break; 17915647eb3SDmitry Kasatkin } 18015647eb3SDmitry Kasatkin 18115647eb3SDmitry Kasatkin if (rc) 18215647eb3SDmitry Kasatkin evm_status = (rc == -ENODATA) ? 18315647eb3SDmitry Kasatkin INTEGRITY_NOXATTRS : INTEGRITY_FAIL; 1847102ebcdSMimi Zohar out: 1857102ebcdSMimi Zohar if (iint) 1867102ebcdSMimi Zohar iint->evm_status = evm_status; 18715647eb3SDmitry Kasatkin kfree(xattr_data); 1887102ebcdSMimi Zohar return evm_status; 18966dbc325SMimi Zohar } 19066dbc325SMimi Zohar 19166dbc325SMimi Zohar static int evm_protected_xattr(const char *req_xattr_name) 19266dbc325SMimi Zohar { 19366dbc325SMimi Zohar char **xattrname; 19466dbc325SMimi Zohar int namelen; 19566dbc325SMimi Zohar int found = 0; 19666dbc325SMimi Zohar 19766dbc325SMimi Zohar namelen = strlen(req_xattr_name); 19866dbc325SMimi Zohar for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { 19966dbc325SMimi Zohar if ((strlen(*xattrname) == namelen) 20066dbc325SMimi Zohar && (strncmp(req_xattr_name, *xattrname, namelen) == 0)) { 20166dbc325SMimi Zohar found = 1; 20266dbc325SMimi Zohar break; 20366dbc325SMimi Zohar } 204cb723180SMimi Zohar if (strncmp(req_xattr_name, 205cb723180SMimi Zohar *xattrname + XATTR_SECURITY_PREFIX_LEN, 206cb723180SMimi Zohar strlen(req_xattr_name)) == 0) { 207cb723180SMimi Zohar found = 1; 208cb723180SMimi Zohar break; 209cb723180SMimi Zohar } 21066dbc325SMimi Zohar } 21166dbc325SMimi Zohar return found; 21266dbc325SMimi Zohar } 21366dbc325SMimi Zohar 21466dbc325SMimi Zohar /** 21566dbc325SMimi Zohar * evm_verifyxattr - verify the integrity of the requested xattr 21666dbc325SMimi Zohar * @dentry: object of the verify xattr 21766dbc325SMimi Zohar * @xattr_name: requested xattr 21866dbc325SMimi Zohar * @xattr_value: requested xattr value 21966dbc325SMimi Zohar * @xattr_value_len: requested xattr value length 22066dbc325SMimi Zohar * 22166dbc325SMimi Zohar * Calculate the HMAC for the given dentry and verify it against the stored 22266dbc325SMimi Zohar * security.evm xattr. For performance, use the xattr value and length 22366dbc325SMimi Zohar * previously retrieved to calculate the HMAC. 22466dbc325SMimi Zohar * 22566dbc325SMimi Zohar * Returns the xattr integrity status. 22666dbc325SMimi Zohar * 22766dbc325SMimi Zohar * This function requires the caller to lock the inode's i_mutex before it 22866dbc325SMimi Zohar * is executed. 22966dbc325SMimi Zohar */ 23066dbc325SMimi Zohar enum integrity_status evm_verifyxattr(struct dentry *dentry, 23166dbc325SMimi Zohar const char *xattr_name, 2322960e6cbSDmitry Kasatkin void *xattr_value, size_t xattr_value_len, 2332960e6cbSDmitry Kasatkin struct integrity_iint_cache *iint) 23466dbc325SMimi Zohar { 23566dbc325SMimi Zohar if (!evm_initialized || !evm_protected_xattr(xattr_name)) 23666dbc325SMimi Zohar return INTEGRITY_UNKNOWN; 23766dbc325SMimi Zohar 2382960e6cbSDmitry Kasatkin if (!iint) { 239c6f493d6SDavid Howells iint = integrity_iint_find(d_backing_inode(dentry)); 24066dbc325SMimi Zohar if (!iint) 24166dbc325SMimi Zohar return INTEGRITY_UNKNOWN; 2422960e6cbSDmitry Kasatkin } 2432960e6cbSDmitry Kasatkin return evm_verify_hmac(dentry, xattr_name, xattr_value, 24466dbc325SMimi Zohar xattr_value_len, iint); 24566dbc325SMimi Zohar } 24666dbc325SMimi Zohar EXPORT_SYMBOL_GPL(evm_verifyxattr); 24766dbc325SMimi Zohar 24866dbc325SMimi Zohar /* 2497102ebcdSMimi Zohar * evm_verify_current_integrity - verify the dentry's metadata integrity 2507102ebcdSMimi Zohar * @dentry: pointer to the affected dentry 2517102ebcdSMimi Zohar * 2527102ebcdSMimi Zohar * Verify and return the dentry's metadata integrity. The exceptions are 2537102ebcdSMimi Zohar * before EVM is initialized or in 'fix' mode. 2547102ebcdSMimi Zohar */ 2557102ebcdSMimi Zohar static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) 2567102ebcdSMimi Zohar { 257c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 2587102ebcdSMimi Zohar 2597102ebcdSMimi Zohar if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode) 2607102ebcdSMimi Zohar return 0; 2617102ebcdSMimi Zohar return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); 2627102ebcdSMimi Zohar } 2637102ebcdSMimi Zohar 264a924ce0bSMimi Zohar /* 265a924ce0bSMimi Zohar * evm_protect_xattr - protect the EVM extended attribute 266a924ce0bSMimi Zohar * 267bf6d0f5dSMimi Zohar * Prevent security.evm from being modified or removed without the 268bf6d0f5dSMimi Zohar * necessary permissions or when the existing value is invalid. 269bf6d0f5dSMimi Zohar * 270bf6d0f5dSMimi Zohar * The posix xattr acls are 'system' prefixed, which normally would not 271bf6d0f5dSMimi Zohar * affect security.evm. An interesting side affect of writing posix xattr 272bf6d0f5dSMimi Zohar * acls is their modifying of the i_mode, which is included in security.evm. 273bf6d0f5dSMimi Zohar * For posix xattr acls only, permit security.evm, even if it currently 274bf6d0f5dSMimi Zohar * doesn't exist, to be updated. 275a924ce0bSMimi Zohar */ 276a924ce0bSMimi Zohar static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, 277a924ce0bSMimi Zohar const void *xattr_value, size_t xattr_value_len) 278a924ce0bSMimi Zohar { 279a924ce0bSMimi Zohar enum integrity_status evm_status; 280a924ce0bSMimi Zohar 281a924ce0bSMimi Zohar if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 282a924ce0bSMimi Zohar if (!capable(CAP_SYS_ADMIN)) 283a924ce0bSMimi Zohar return -EPERM; 284bf6d0f5dSMimi Zohar } else if (!evm_protected_xattr(xattr_name)) { 285bf6d0f5dSMimi Zohar if (!posix_xattr_acl(xattr_name)) 286a924ce0bSMimi Zohar return 0; 287bf6d0f5dSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 288bf6d0f5dSMimi Zohar if ((evm_status == INTEGRITY_PASS) || 289566be59aSMimi Zohar (evm_status == INTEGRITY_NOXATTRS)) 290bf6d0f5dSMimi Zohar return 0; 2919b97b6cdSMimi Zohar goto out; 292bf6d0f5dSMimi Zohar } 293a924ce0bSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 2943dcbad52SDmitry Kasatkin if (evm_status == INTEGRITY_NOXATTRS) { 2953dcbad52SDmitry Kasatkin struct integrity_iint_cache *iint; 2963dcbad52SDmitry Kasatkin 297c6f493d6SDavid Howells iint = integrity_iint_find(d_backing_inode(dentry)); 2983dcbad52SDmitry Kasatkin if (iint && (iint->flags & IMA_NEW_FILE)) 2993dcbad52SDmitry Kasatkin return 0; 3005101a185SMimi Zohar 3015101a185SMimi Zohar /* exception for pseudo filesystems */ 302fc64005cSAl Viro if (dentry->d_sb->s_magic == TMPFS_MAGIC 303fc64005cSAl Viro || dentry->d_sb->s_magic == SYSFS_MAGIC) 3045101a185SMimi Zohar return 0; 3055101a185SMimi Zohar 3065101a185SMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_METADATA, 3075101a185SMimi Zohar dentry->d_inode, dentry->d_name.name, 3085101a185SMimi Zohar "update_metadata", 3095101a185SMimi Zohar integrity_status_msg[evm_status], 3105101a185SMimi Zohar -EPERM, 0); 3113dcbad52SDmitry Kasatkin } 3129b97b6cdSMimi Zohar out: 3139b97b6cdSMimi Zohar if (evm_status != INTEGRITY_PASS) 314c6f493d6SDavid Howells integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 3159b97b6cdSMimi Zohar dentry->d_name.name, "appraise_metadata", 3169b97b6cdSMimi Zohar integrity_status_msg[evm_status], 3179b97b6cdSMimi Zohar -EPERM, 0); 318a924ce0bSMimi Zohar return evm_status == INTEGRITY_PASS ? 0 : -EPERM; 319a924ce0bSMimi Zohar } 320a924ce0bSMimi Zohar 32166dbc325SMimi Zohar /** 32266dbc325SMimi Zohar * evm_inode_setxattr - protect the EVM extended attribute 32366dbc325SMimi Zohar * @dentry: pointer to the affected dentry 32466dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 32566dbc325SMimi Zohar * @xattr_value: pointer to the new extended attribute value 32666dbc325SMimi Zohar * @xattr_value_len: pointer to the new extended attribute value length 32766dbc325SMimi Zohar * 3282fb1c9a4SMimi Zohar * Before allowing the 'security.evm' protected xattr to be updated, 3292fb1c9a4SMimi Zohar * verify the existing value is valid. As only the kernel should have 3302fb1c9a4SMimi Zohar * access to the EVM encrypted key needed to calculate the HMAC, prevent 3312fb1c9a4SMimi Zohar * userspace from writing HMAC value. Writing 'security.evm' requires 3322fb1c9a4SMimi Zohar * requires CAP_SYS_ADMIN privileges. 33366dbc325SMimi Zohar */ 33466dbc325SMimi Zohar int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, 33566dbc325SMimi Zohar const void *xattr_value, size_t xattr_value_len) 33666dbc325SMimi Zohar { 3372fb1c9a4SMimi Zohar const struct evm_ima_xattr_data *xattr_data = xattr_value; 3382fb1c9a4SMimi Zohar 3393b1deef6SDmitry Kasatkin if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 3403b1deef6SDmitry Kasatkin if (!xattr_value_len) 3413b1deef6SDmitry Kasatkin return -EINVAL; 3423b1deef6SDmitry Kasatkin if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) 3432fb1c9a4SMimi Zohar return -EPERM; 3443b1deef6SDmitry Kasatkin } 345a924ce0bSMimi Zohar return evm_protect_xattr(dentry, xattr_name, xattr_value, 34666dbc325SMimi Zohar xattr_value_len); 34766dbc325SMimi Zohar } 34866dbc325SMimi Zohar 34966dbc325SMimi Zohar /** 35066dbc325SMimi Zohar * evm_inode_removexattr - protect the EVM extended attribute 35166dbc325SMimi Zohar * @dentry: pointer to the affected dentry 35266dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 35366dbc325SMimi Zohar * 3547102ebcdSMimi Zohar * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that 3557102ebcdSMimi Zohar * the current value is valid. 35666dbc325SMimi Zohar */ 35766dbc325SMimi Zohar int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) 35866dbc325SMimi Zohar { 359a924ce0bSMimi Zohar return evm_protect_xattr(dentry, xattr_name, NULL, 0); 36066dbc325SMimi Zohar } 36166dbc325SMimi Zohar 362523b74b1SDmitry Kasatkin static void evm_reset_status(struct inode *inode) 363523b74b1SDmitry Kasatkin { 364523b74b1SDmitry Kasatkin struct integrity_iint_cache *iint; 365523b74b1SDmitry Kasatkin 366523b74b1SDmitry Kasatkin iint = integrity_iint_find(inode); 367523b74b1SDmitry Kasatkin if (iint) 368523b74b1SDmitry Kasatkin iint->evm_status = INTEGRITY_UNKNOWN; 369523b74b1SDmitry Kasatkin } 370523b74b1SDmitry Kasatkin 37166dbc325SMimi Zohar /** 37266dbc325SMimi Zohar * evm_inode_post_setxattr - update 'security.evm' to reflect the changes 37366dbc325SMimi Zohar * @dentry: pointer to the affected dentry 37466dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 37566dbc325SMimi Zohar * @xattr_value: pointer to the new extended attribute value 37666dbc325SMimi Zohar * @xattr_value_len: pointer to the new extended attribute value length 37766dbc325SMimi Zohar * 37866dbc325SMimi Zohar * Update the HMAC stored in 'security.evm' to reflect the change. 37966dbc325SMimi Zohar * 38066dbc325SMimi Zohar * No need to take the i_mutex lock here, as this function is called from 38166dbc325SMimi Zohar * __vfs_setxattr_noperm(). The caller of which has taken the inode's 38266dbc325SMimi Zohar * i_mutex lock. 38366dbc325SMimi Zohar */ 38466dbc325SMimi Zohar void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, 38566dbc325SMimi Zohar const void *xattr_value, size_t xattr_value_len) 38666dbc325SMimi Zohar { 387bf6d0f5dSMimi Zohar if (!evm_initialized || (!evm_protected_xattr(xattr_name) 388bf6d0f5dSMimi Zohar && !posix_xattr_acl(xattr_name))) 38966dbc325SMimi Zohar return; 39066dbc325SMimi Zohar 391523b74b1SDmitry Kasatkin evm_reset_status(dentry->d_inode); 392523b74b1SDmitry Kasatkin 39366dbc325SMimi Zohar evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); 39466dbc325SMimi Zohar } 39566dbc325SMimi Zohar 39666dbc325SMimi Zohar /** 39766dbc325SMimi Zohar * evm_inode_post_removexattr - update 'security.evm' after removing the xattr 39866dbc325SMimi Zohar * @dentry: pointer to the affected dentry 39966dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 40066dbc325SMimi Zohar * 40166dbc325SMimi Zohar * Update the HMAC stored in 'security.evm' to reflect removal of the xattr. 4027c51bb00SDmitry Kasatkin * 4037c51bb00SDmitry Kasatkin * No need to take the i_mutex lock here, as this function is called from 4047c51bb00SDmitry Kasatkin * vfs_removexattr() which takes the i_mutex. 40566dbc325SMimi Zohar */ 40666dbc325SMimi Zohar void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) 40766dbc325SMimi Zohar { 40866dbc325SMimi Zohar if (!evm_initialized || !evm_protected_xattr(xattr_name)) 40966dbc325SMimi Zohar return; 41066dbc325SMimi Zohar 411523b74b1SDmitry Kasatkin evm_reset_status(dentry->d_inode); 412523b74b1SDmitry Kasatkin 41366dbc325SMimi Zohar evm_update_evmxattr(dentry, xattr_name, NULL, 0); 41466dbc325SMimi Zohar } 41566dbc325SMimi Zohar 41666dbc325SMimi Zohar /** 417817b54aaSMimi Zohar * evm_inode_setattr - prevent updating an invalid EVM extended attribute 418817b54aaSMimi Zohar * @dentry: pointer to the affected dentry 419817b54aaSMimi Zohar */ 420817b54aaSMimi Zohar int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) 421817b54aaSMimi Zohar { 422817b54aaSMimi Zohar unsigned int ia_valid = attr->ia_valid; 423817b54aaSMimi Zohar enum integrity_status evm_status; 424817b54aaSMimi Zohar 425a924ce0bSMimi Zohar if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) 426817b54aaSMimi Zohar return 0; 427817b54aaSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 428566be59aSMimi Zohar if ((evm_status == INTEGRITY_PASS) || 429566be59aSMimi Zohar (evm_status == INTEGRITY_NOXATTRS)) 430566be59aSMimi Zohar return 0; 431c6f493d6SDavid Howells integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 4329b97b6cdSMimi Zohar dentry->d_name.name, "appraise_metadata", 4339b97b6cdSMimi Zohar integrity_status_msg[evm_status], -EPERM, 0); 434566be59aSMimi Zohar return -EPERM; 435817b54aaSMimi Zohar } 436817b54aaSMimi Zohar 437817b54aaSMimi Zohar /** 43866dbc325SMimi Zohar * evm_inode_post_setattr - update 'security.evm' after modifying metadata 43966dbc325SMimi Zohar * @dentry: pointer to the affected dentry 44066dbc325SMimi Zohar * @ia_valid: for the UID and GID status 44166dbc325SMimi Zohar * 44266dbc325SMimi Zohar * For now, update the HMAC stored in 'security.evm' to reflect UID/GID 44366dbc325SMimi Zohar * changes. 44466dbc325SMimi Zohar * 44566dbc325SMimi Zohar * This function is called from notify_change(), which expects the caller 44666dbc325SMimi Zohar * to lock the inode's i_mutex. 44766dbc325SMimi Zohar */ 44866dbc325SMimi Zohar void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) 44966dbc325SMimi Zohar { 45066dbc325SMimi Zohar if (!evm_initialized) 45166dbc325SMimi Zohar return; 45266dbc325SMimi Zohar 45366dbc325SMimi Zohar if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) 45466dbc325SMimi Zohar evm_update_evmxattr(dentry, NULL, NULL, 0); 45566dbc325SMimi Zohar } 45666dbc325SMimi Zohar 457cb723180SMimi Zohar /* 458cb723180SMimi Zohar * evm_inode_init_security - initializes security.evm 459cb723180SMimi Zohar */ 460cb723180SMimi Zohar int evm_inode_init_security(struct inode *inode, 461cb723180SMimi Zohar const struct xattr *lsm_xattr, 462cb723180SMimi Zohar struct xattr *evm_xattr) 463cb723180SMimi Zohar { 464cb723180SMimi Zohar struct evm_ima_xattr_data *xattr_data; 465cb723180SMimi Zohar int rc; 466cb723180SMimi Zohar 467cb723180SMimi Zohar if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name)) 4685a4730baSMimi Zohar return 0; 469cb723180SMimi Zohar 470cb723180SMimi Zohar xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS); 471cb723180SMimi Zohar if (!xattr_data) 472cb723180SMimi Zohar return -ENOMEM; 473cb723180SMimi Zohar 474cb723180SMimi Zohar xattr_data->type = EVM_XATTR_HMAC; 475cb723180SMimi Zohar rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest); 476cb723180SMimi Zohar if (rc < 0) 477cb723180SMimi Zohar goto out; 478cb723180SMimi Zohar 479cb723180SMimi Zohar evm_xattr->value = xattr_data; 480cb723180SMimi Zohar evm_xattr->value_len = sizeof(*xattr_data); 4819548906bSTetsuo Handa evm_xattr->name = XATTR_EVM_SUFFIX; 482cb723180SMimi Zohar return 0; 483cb723180SMimi Zohar out: 484cb723180SMimi Zohar kfree(xattr_data); 485cb723180SMimi Zohar return rc; 486cb723180SMimi Zohar } 487cb723180SMimi Zohar EXPORT_SYMBOL_GPL(evm_inode_init_security); 488cb723180SMimi Zohar 4892ce523ebSDmitry Kasatkin #ifdef CONFIG_EVM_LOAD_X509 4902ce523ebSDmitry Kasatkin void __init evm_load_x509(void) 4912ce523ebSDmitry Kasatkin { 49226ddabfeSDmitry Kasatkin int rc; 49326ddabfeSDmitry Kasatkin 49426ddabfeSDmitry Kasatkin rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH); 49526ddabfeSDmitry Kasatkin if (!rc) 49626ddabfeSDmitry Kasatkin evm_initialized |= EVM_INIT_X509; 4972ce523ebSDmitry Kasatkin } 4982ce523ebSDmitry Kasatkin #endif 4992ce523ebSDmitry Kasatkin 50066dbc325SMimi Zohar static int __init init_evm(void) 50166dbc325SMimi Zohar { 50266dbc325SMimi Zohar int error; 50366dbc325SMimi Zohar 504d3b33679SDmitry Kasatkin evm_init_config(); 505d3b33679SDmitry Kasatkin 506f4dc3778SDmitry Kasatkin error = integrity_init_keyring(INTEGRITY_KEYRING_EVM); 507f4dc3778SDmitry Kasatkin if (error) 508f4dc3778SDmitry Kasatkin return error; 509f4dc3778SDmitry Kasatkin 51066dbc325SMimi Zohar error = evm_init_secfs(); 51166dbc325SMimi Zohar if (error < 0) { 51220ee451fSJoe Perches pr_info("Error registering secfs\n"); 513f4dc3778SDmitry Kasatkin return error; 51466dbc325SMimi Zohar } 51515647eb3SDmitry Kasatkin 51615647eb3SDmitry Kasatkin return 0; 51766dbc325SMimi Zohar } 51866dbc325SMimi Zohar 51966dbc325SMimi Zohar /* 52066dbc325SMimi Zohar * evm_display_config - list the EVM protected security extended attributes 52166dbc325SMimi Zohar */ 52266dbc325SMimi Zohar static int __init evm_display_config(void) 52366dbc325SMimi Zohar { 52466dbc325SMimi Zohar char **xattrname; 52566dbc325SMimi Zohar 52666dbc325SMimi Zohar for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) 52720ee451fSJoe Perches pr_info("%s\n", *xattrname); 52866dbc325SMimi Zohar return 0; 52966dbc325SMimi Zohar } 53066dbc325SMimi Zohar 53166dbc325SMimi Zohar pure_initcall(evm_display_config); 53266dbc325SMimi Zohar late_initcall(init_evm); 53366dbc325SMimi Zohar 53466dbc325SMimi Zohar MODULE_DESCRIPTION("Extended Verification Module"); 53566dbc325SMimi Zohar MODULE_LICENSE("GPL"); 536