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 815d6c3191SAndreas Gruenbacher if (!(inode->i_opflags & IOP_XATTR)) 8215647eb3SDmitry Kasatkin return -EOPNOTSUPP; 8315647eb3SDmitry Kasatkin 8415647eb3SDmitry Kasatkin for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { 855d6c3191SAndreas Gruenbacher error = __vfs_getxattr(dentry, inode, *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: 148b4bfec7fSSeth Forshee if (xattr_len != sizeof(struct evm_ima_xattr_data)) { 149b4bfec7fSSeth Forshee evm_status = INTEGRITY_FAIL; 150b4bfec7fSSeth Forshee goto out; 151b4bfec7fSSeth Forshee } 15215647eb3SDmitry Kasatkin rc = evm_calc_hmac(dentry, xattr_name, xattr_value, 15315647eb3SDmitry Kasatkin xattr_value_len, calc.digest); 15415647eb3SDmitry Kasatkin if (rc) 15515647eb3SDmitry Kasatkin break; 156613317bdSRyan Ware rc = crypto_memneq(xattr_data->digest, calc.digest, 15715647eb3SDmitry Kasatkin sizeof(calc.digest)); 15815647eb3SDmitry Kasatkin if (rc) 15915647eb3SDmitry Kasatkin rc = -EINVAL; 16015647eb3SDmitry Kasatkin break; 16115647eb3SDmitry Kasatkin case EVM_IMA_XATTR_DIGSIG: 16215647eb3SDmitry Kasatkin rc = evm_calc_hash(dentry, xattr_name, xattr_value, 16315647eb3SDmitry Kasatkin xattr_value_len, calc.digest); 16415647eb3SDmitry Kasatkin if (rc) 16515647eb3SDmitry Kasatkin break; 16615647eb3SDmitry Kasatkin rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, 167b1aaab22SDmitry Kasatkin (const char *)xattr_data, xattr_len, 16815647eb3SDmitry Kasatkin calc.digest, sizeof(calc.digest)); 16915647eb3SDmitry Kasatkin if (!rc) { 170c2baec7fSDmitry Kasatkin /* Replace RSA with HMAC if not mounted readonly and 171c2baec7fSDmitry Kasatkin * not immutable 172c2baec7fSDmitry Kasatkin */ 173c6f493d6SDavid Howells if (!IS_RDONLY(d_backing_inode(dentry)) && 174c6f493d6SDavid Howells !IS_IMMUTABLE(d_backing_inode(dentry))) 175c2baec7fSDmitry Kasatkin evm_update_evmxattr(dentry, xattr_name, 176c2baec7fSDmitry Kasatkin xattr_value, 17715647eb3SDmitry Kasatkin xattr_value_len); 17815647eb3SDmitry Kasatkin } 17915647eb3SDmitry Kasatkin break; 18015647eb3SDmitry Kasatkin default: 18115647eb3SDmitry Kasatkin rc = -EINVAL; 18215647eb3SDmitry Kasatkin break; 18315647eb3SDmitry Kasatkin } 18415647eb3SDmitry Kasatkin 18515647eb3SDmitry Kasatkin if (rc) 18615647eb3SDmitry Kasatkin evm_status = (rc == -ENODATA) ? 18715647eb3SDmitry Kasatkin INTEGRITY_NOXATTRS : INTEGRITY_FAIL; 1887102ebcdSMimi Zohar out: 1897102ebcdSMimi Zohar if (iint) 1907102ebcdSMimi Zohar iint->evm_status = evm_status; 19115647eb3SDmitry Kasatkin kfree(xattr_data); 1927102ebcdSMimi Zohar return evm_status; 19366dbc325SMimi Zohar } 19466dbc325SMimi Zohar 19566dbc325SMimi Zohar static int evm_protected_xattr(const char *req_xattr_name) 19666dbc325SMimi Zohar { 19766dbc325SMimi Zohar char **xattrname; 19866dbc325SMimi Zohar int namelen; 19966dbc325SMimi Zohar int found = 0; 20066dbc325SMimi Zohar 20166dbc325SMimi Zohar namelen = strlen(req_xattr_name); 20266dbc325SMimi Zohar for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { 20366dbc325SMimi Zohar if ((strlen(*xattrname) == namelen) 20466dbc325SMimi Zohar && (strncmp(req_xattr_name, *xattrname, namelen) == 0)) { 20566dbc325SMimi Zohar found = 1; 20666dbc325SMimi Zohar break; 20766dbc325SMimi Zohar } 208cb723180SMimi Zohar if (strncmp(req_xattr_name, 209cb723180SMimi Zohar *xattrname + XATTR_SECURITY_PREFIX_LEN, 210cb723180SMimi Zohar strlen(req_xattr_name)) == 0) { 211cb723180SMimi Zohar found = 1; 212cb723180SMimi Zohar break; 213cb723180SMimi Zohar } 21466dbc325SMimi Zohar } 21566dbc325SMimi Zohar return found; 21666dbc325SMimi Zohar } 21766dbc325SMimi Zohar 21866dbc325SMimi Zohar /** 21966dbc325SMimi Zohar * evm_verifyxattr - verify the integrity of the requested xattr 22066dbc325SMimi Zohar * @dentry: object of the verify xattr 22166dbc325SMimi Zohar * @xattr_name: requested xattr 22266dbc325SMimi Zohar * @xattr_value: requested xattr value 22366dbc325SMimi Zohar * @xattr_value_len: requested xattr value length 22466dbc325SMimi Zohar * 22566dbc325SMimi Zohar * Calculate the HMAC for the given dentry and verify it against the stored 22666dbc325SMimi Zohar * security.evm xattr. For performance, use the xattr value and length 22766dbc325SMimi Zohar * previously retrieved to calculate the HMAC. 22866dbc325SMimi Zohar * 22966dbc325SMimi Zohar * Returns the xattr integrity status. 23066dbc325SMimi Zohar * 23166dbc325SMimi Zohar * This function requires the caller to lock the inode's i_mutex before it 23266dbc325SMimi Zohar * is executed. 23366dbc325SMimi Zohar */ 23466dbc325SMimi Zohar enum integrity_status evm_verifyxattr(struct dentry *dentry, 23566dbc325SMimi Zohar const char *xattr_name, 2362960e6cbSDmitry Kasatkin void *xattr_value, size_t xattr_value_len, 2372960e6cbSDmitry Kasatkin struct integrity_iint_cache *iint) 23866dbc325SMimi Zohar { 23966dbc325SMimi Zohar if (!evm_initialized || !evm_protected_xattr(xattr_name)) 24066dbc325SMimi Zohar return INTEGRITY_UNKNOWN; 24166dbc325SMimi Zohar 2422960e6cbSDmitry Kasatkin if (!iint) { 243c6f493d6SDavid Howells iint = integrity_iint_find(d_backing_inode(dentry)); 24466dbc325SMimi Zohar if (!iint) 24566dbc325SMimi Zohar return INTEGRITY_UNKNOWN; 2462960e6cbSDmitry Kasatkin } 2472960e6cbSDmitry Kasatkin return evm_verify_hmac(dentry, xattr_name, xattr_value, 24866dbc325SMimi Zohar xattr_value_len, iint); 24966dbc325SMimi Zohar } 25066dbc325SMimi Zohar EXPORT_SYMBOL_GPL(evm_verifyxattr); 25166dbc325SMimi Zohar 25266dbc325SMimi Zohar /* 2537102ebcdSMimi Zohar * evm_verify_current_integrity - verify the dentry's metadata integrity 2547102ebcdSMimi Zohar * @dentry: pointer to the affected dentry 2557102ebcdSMimi Zohar * 2567102ebcdSMimi Zohar * Verify and return the dentry's metadata integrity. The exceptions are 2577102ebcdSMimi Zohar * before EVM is initialized or in 'fix' mode. 2587102ebcdSMimi Zohar */ 2597102ebcdSMimi Zohar static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) 2607102ebcdSMimi Zohar { 261c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 2627102ebcdSMimi Zohar 2637102ebcdSMimi Zohar if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode) 2647102ebcdSMimi Zohar return 0; 2657102ebcdSMimi Zohar return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); 2667102ebcdSMimi Zohar } 2677102ebcdSMimi Zohar 268a924ce0bSMimi Zohar /* 269a924ce0bSMimi Zohar * evm_protect_xattr - protect the EVM extended attribute 270a924ce0bSMimi Zohar * 271bf6d0f5dSMimi Zohar * Prevent security.evm from being modified or removed without the 272bf6d0f5dSMimi Zohar * necessary permissions or when the existing value is invalid. 273bf6d0f5dSMimi Zohar * 274bf6d0f5dSMimi Zohar * The posix xattr acls are 'system' prefixed, which normally would not 275bf6d0f5dSMimi Zohar * affect security.evm. An interesting side affect of writing posix xattr 276bf6d0f5dSMimi Zohar * acls is their modifying of the i_mode, which is included in security.evm. 277bf6d0f5dSMimi Zohar * For posix xattr acls only, permit security.evm, even if it currently 278bf6d0f5dSMimi Zohar * doesn't exist, to be updated. 279a924ce0bSMimi Zohar */ 280a924ce0bSMimi Zohar static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, 281a924ce0bSMimi Zohar const void *xattr_value, size_t xattr_value_len) 282a924ce0bSMimi Zohar { 283a924ce0bSMimi Zohar enum integrity_status evm_status; 284a924ce0bSMimi Zohar 285a924ce0bSMimi Zohar if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 286a924ce0bSMimi Zohar if (!capable(CAP_SYS_ADMIN)) 287a924ce0bSMimi Zohar return -EPERM; 288bf6d0f5dSMimi Zohar } else if (!evm_protected_xattr(xattr_name)) { 289bf6d0f5dSMimi Zohar if (!posix_xattr_acl(xattr_name)) 290a924ce0bSMimi Zohar return 0; 291bf6d0f5dSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 292bf6d0f5dSMimi Zohar if ((evm_status == INTEGRITY_PASS) || 293566be59aSMimi Zohar (evm_status == INTEGRITY_NOXATTRS)) 294bf6d0f5dSMimi Zohar return 0; 2959b97b6cdSMimi Zohar goto out; 296bf6d0f5dSMimi Zohar } 297a924ce0bSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 2983dcbad52SDmitry Kasatkin if (evm_status == INTEGRITY_NOXATTRS) { 2993dcbad52SDmitry Kasatkin struct integrity_iint_cache *iint; 3003dcbad52SDmitry Kasatkin 301c6f493d6SDavid Howells iint = integrity_iint_find(d_backing_inode(dentry)); 3023dcbad52SDmitry Kasatkin if (iint && (iint->flags & IMA_NEW_FILE)) 3033dcbad52SDmitry Kasatkin return 0; 3045101a185SMimi Zohar 3055101a185SMimi Zohar /* exception for pseudo filesystems */ 306fc64005cSAl Viro if (dentry->d_sb->s_magic == TMPFS_MAGIC 307fc64005cSAl Viro || dentry->d_sb->s_magic == SYSFS_MAGIC) 3085101a185SMimi Zohar return 0; 3095101a185SMimi Zohar 3105101a185SMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_METADATA, 3115101a185SMimi Zohar dentry->d_inode, dentry->d_name.name, 3125101a185SMimi Zohar "update_metadata", 3135101a185SMimi Zohar integrity_status_msg[evm_status], 3145101a185SMimi Zohar -EPERM, 0); 3153dcbad52SDmitry Kasatkin } 3169b97b6cdSMimi Zohar out: 3179b97b6cdSMimi Zohar if (evm_status != INTEGRITY_PASS) 318c6f493d6SDavid Howells integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 3199b97b6cdSMimi Zohar dentry->d_name.name, "appraise_metadata", 3209b97b6cdSMimi Zohar integrity_status_msg[evm_status], 3219b97b6cdSMimi Zohar -EPERM, 0); 322a924ce0bSMimi Zohar return evm_status == INTEGRITY_PASS ? 0 : -EPERM; 323a924ce0bSMimi Zohar } 324a924ce0bSMimi Zohar 32566dbc325SMimi Zohar /** 32666dbc325SMimi Zohar * evm_inode_setxattr - protect the EVM extended attribute 32766dbc325SMimi Zohar * @dentry: pointer to the affected dentry 32866dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 32966dbc325SMimi Zohar * @xattr_value: pointer to the new extended attribute value 33066dbc325SMimi Zohar * @xattr_value_len: pointer to the new extended attribute value length 33166dbc325SMimi Zohar * 3322fb1c9a4SMimi Zohar * Before allowing the 'security.evm' protected xattr to be updated, 3332fb1c9a4SMimi Zohar * verify the existing value is valid. As only the kernel should have 3342fb1c9a4SMimi Zohar * access to the EVM encrypted key needed to calculate the HMAC, prevent 3352fb1c9a4SMimi Zohar * userspace from writing HMAC value. Writing 'security.evm' requires 3362fb1c9a4SMimi Zohar * requires CAP_SYS_ADMIN privileges. 33766dbc325SMimi Zohar */ 33866dbc325SMimi Zohar int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, 33966dbc325SMimi Zohar const void *xattr_value, size_t xattr_value_len) 34066dbc325SMimi Zohar { 3412fb1c9a4SMimi Zohar const struct evm_ima_xattr_data *xattr_data = xattr_value; 3422fb1c9a4SMimi Zohar 3433b1deef6SDmitry Kasatkin if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { 3443b1deef6SDmitry Kasatkin if (!xattr_value_len) 3453b1deef6SDmitry Kasatkin return -EINVAL; 3463b1deef6SDmitry Kasatkin if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) 3472fb1c9a4SMimi Zohar return -EPERM; 3483b1deef6SDmitry Kasatkin } 349a924ce0bSMimi Zohar return evm_protect_xattr(dentry, xattr_name, xattr_value, 35066dbc325SMimi Zohar xattr_value_len); 35166dbc325SMimi Zohar } 35266dbc325SMimi Zohar 35366dbc325SMimi Zohar /** 35466dbc325SMimi Zohar * evm_inode_removexattr - protect the EVM extended attribute 35566dbc325SMimi Zohar * @dentry: pointer to the affected dentry 35666dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 35766dbc325SMimi Zohar * 3587102ebcdSMimi Zohar * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that 3597102ebcdSMimi Zohar * the current value is valid. 36066dbc325SMimi Zohar */ 36166dbc325SMimi Zohar int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) 36266dbc325SMimi Zohar { 363a924ce0bSMimi Zohar return evm_protect_xattr(dentry, xattr_name, NULL, 0); 36466dbc325SMimi Zohar } 36566dbc325SMimi Zohar 366523b74b1SDmitry Kasatkin static void evm_reset_status(struct inode *inode) 367523b74b1SDmitry Kasatkin { 368523b74b1SDmitry Kasatkin struct integrity_iint_cache *iint; 369523b74b1SDmitry Kasatkin 370523b74b1SDmitry Kasatkin iint = integrity_iint_find(inode); 371523b74b1SDmitry Kasatkin if (iint) 372523b74b1SDmitry Kasatkin iint->evm_status = INTEGRITY_UNKNOWN; 373523b74b1SDmitry Kasatkin } 374523b74b1SDmitry Kasatkin 37566dbc325SMimi Zohar /** 37666dbc325SMimi Zohar * evm_inode_post_setxattr - update 'security.evm' to reflect the changes 37766dbc325SMimi Zohar * @dentry: pointer to the affected dentry 37866dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 37966dbc325SMimi Zohar * @xattr_value: pointer to the new extended attribute value 38066dbc325SMimi Zohar * @xattr_value_len: pointer to the new extended attribute value length 38166dbc325SMimi Zohar * 38266dbc325SMimi Zohar * Update the HMAC stored in 'security.evm' to reflect the change. 38366dbc325SMimi Zohar * 38466dbc325SMimi Zohar * No need to take the i_mutex lock here, as this function is called from 38566dbc325SMimi Zohar * __vfs_setxattr_noperm(). The caller of which has taken the inode's 38666dbc325SMimi Zohar * i_mutex lock. 38766dbc325SMimi Zohar */ 38866dbc325SMimi Zohar void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, 38966dbc325SMimi Zohar const void *xattr_value, size_t xattr_value_len) 39066dbc325SMimi Zohar { 391bf6d0f5dSMimi Zohar if (!evm_initialized || (!evm_protected_xattr(xattr_name) 392bf6d0f5dSMimi Zohar && !posix_xattr_acl(xattr_name))) 39366dbc325SMimi Zohar return; 39466dbc325SMimi Zohar 395523b74b1SDmitry Kasatkin evm_reset_status(dentry->d_inode); 396523b74b1SDmitry Kasatkin 39766dbc325SMimi Zohar evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); 39866dbc325SMimi Zohar } 39966dbc325SMimi Zohar 40066dbc325SMimi Zohar /** 40166dbc325SMimi Zohar * evm_inode_post_removexattr - update 'security.evm' after removing the xattr 40266dbc325SMimi Zohar * @dentry: pointer to the affected dentry 40366dbc325SMimi Zohar * @xattr_name: pointer to the affected extended attribute name 40466dbc325SMimi Zohar * 40566dbc325SMimi Zohar * Update the HMAC stored in 'security.evm' to reflect removal of the xattr. 4067c51bb00SDmitry Kasatkin * 4077c51bb00SDmitry Kasatkin * No need to take the i_mutex lock here, as this function is called from 4087c51bb00SDmitry Kasatkin * vfs_removexattr() which takes the i_mutex. 40966dbc325SMimi Zohar */ 41066dbc325SMimi Zohar void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) 41166dbc325SMimi Zohar { 41266dbc325SMimi Zohar if (!evm_initialized || !evm_protected_xattr(xattr_name)) 41366dbc325SMimi Zohar return; 41466dbc325SMimi Zohar 415523b74b1SDmitry Kasatkin evm_reset_status(dentry->d_inode); 416523b74b1SDmitry Kasatkin 41766dbc325SMimi Zohar evm_update_evmxattr(dentry, xattr_name, NULL, 0); 41866dbc325SMimi Zohar } 41966dbc325SMimi Zohar 42066dbc325SMimi Zohar /** 421817b54aaSMimi Zohar * evm_inode_setattr - prevent updating an invalid EVM extended attribute 422817b54aaSMimi Zohar * @dentry: pointer to the affected dentry 423817b54aaSMimi Zohar */ 424817b54aaSMimi Zohar int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) 425817b54aaSMimi Zohar { 426817b54aaSMimi Zohar unsigned int ia_valid = attr->ia_valid; 427817b54aaSMimi Zohar enum integrity_status evm_status; 428817b54aaSMimi Zohar 429a924ce0bSMimi Zohar if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) 430817b54aaSMimi Zohar return 0; 431817b54aaSMimi Zohar evm_status = evm_verify_current_integrity(dentry); 432566be59aSMimi Zohar if ((evm_status == INTEGRITY_PASS) || 433566be59aSMimi Zohar (evm_status == INTEGRITY_NOXATTRS)) 434566be59aSMimi Zohar return 0; 435c6f493d6SDavid Howells integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), 4369b97b6cdSMimi Zohar dentry->d_name.name, "appraise_metadata", 4379b97b6cdSMimi Zohar integrity_status_msg[evm_status], -EPERM, 0); 438566be59aSMimi Zohar return -EPERM; 439817b54aaSMimi Zohar } 440817b54aaSMimi Zohar 441817b54aaSMimi Zohar /** 44266dbc325SMimi Zohar * evm_inode_post_setattr - update 'security.evm' after modifying metadata 44366dbc325SMimi Zohar * @dentry: pointer to the affected dentry 44466dbc325SMimi Zohar * @ia_valid: for the UID and GID status 44566dbc325SMimi Zohar * 44666dbc325SMimi Zohar * For now, update the HMAC stored in 'security.evm' to reflect UID/GID 44766dbc325SMimi Zohar * changes. 44866dbc325SMimi Zohar * 44966dbc325SMimi Zohar * This function is called from notify_change(), which expects the caller 45066dbc325SMimi Zohar * to lock the inode's i_mutex. 45166dbc325SMimi Zohar */ 45266dbc325SMimi Zohar void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) 45366dbc325SMimi Zohar { 45466dbc325SMimi Zohar if (!evm_initialized) 45566dbc325SMimi Zohar return; 45666dbc325SMimi Zohar 45766dbc325SMimi Zohar if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) 45866dbc325SMimi Zohar evm_update_evmxattr(dentry, NULL, NULL, 0); 45966dbc325SMimi Zohar } 46066dbc325SMimi Zohar 461cb723180SMimi Zohar /* 462cb723180SMimi Zohar * evm_inode_init_security - initializes security.evm 463cb723180SMimi Zohar */ 464cb723180SMimi Zohar int evm_inode_init_security(struct inode *inode, 465cb723180SMimi Zohar const struct xattr *lsm_xattr, 466cb723180SMimi Zohar struct xattr *evm_xattr) 467cb723180SMimi Zohar { 468cb723180SMimi Zohar struct evm_ima_xattr_data *xattr_data; 469cb723180SMimi Zohar int rc; 470cb723180SMimi Zohar 471cb723180SMimi Zohar if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name)) 4725a4730baSMimi Zohar return 0; 473cb723180SMimi Zohar 474cb723180SMimi Zohar xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS); 475cb723180SMimi Zohar if (!xattr_data) 476cb723180SMimi Zohar return -ENOMEM; 477cb723180SMimi Zohar 478cb723180SMimi Zohar xattr_data->type = EVM_XATTR_HMAC; 479cb723180SMimi Zohar rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest); 480cb723180SMimi Zohar if (rc < 0) 481cb723180SMimi Zohar goto out; 482cb723180SMimi Zohar 483cb723180SMimi Zohar evm_xattr->value = xattr_data; 484cb723180SMimi Zohar evm_xattr->value_len = sizeof(*xattr_data); 4859548906bSTetsuo Handa evm_xattr->name = XATTR_EVM_SUFFIX; 486cb723180SMimi Zohar return 0; 487cb723180SMimi Zohar out: 488cb723180SMimi Zohar kfree(xattr_data); 489cb723180SMimi Zohar return rc; 490cb723180SMimi Zohar } 491cb723180SMimi Zohar EXPORT_SYMBOL_GPL(evm_inode_init_security); 492cb723180SMimi Zohar 4932ce523ebSDmitry Kasatkin #ifdef CONFIG_EVM_LOAD_X509 4942ce523ebSDmitry Kasatkin void __init evm_load_x509(void) 4952ce523ebSDmitry Kasatkin { 49626ddabfeSDmitry Kasatkin int rc; 49726ddabfeSDmitry Kasatkin 49826ddabfeSDmitry Kasatkin rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH); 49926ddabfeSDmitry Kasatkin if (!rc) 50026ddabfeSDmitry Kasatkin evm_initialized |= EVM_INIT_X509; 5012ce523ebSDmitry Kasatkin } 5022ce523ebSDmitry Kasatkin #endif 5032ce523ebSDmitry Kasatkin 50466dbc325SMimi Zohar static int __init init_evm(void) 50566dbc325SMimi Zohar { 50666dbc325SMimi Zohar int error; 50766dbc325SMimi Zohar 508d3b33679SDmitry Kasatkin evm_init_config(); 509d3b33679SDmitry Kasatkin 510f4dc3778SDmitry Kasatkin error = integrity_init_keyring(INTEGRITY_KEYRING_EVM); 511f4dc3778SDmitry Kasatkin if (error) 512f4dc3778SDmitry Kasatkin return error; 513f4dc3778SDmitry Kasatkin 51466dbc325SMimi Zohar error = evm_init_secfs(); 51566dbc325SMimi Zohar if (error < 0) { 51620ee451fSJoe Perches pr_info("Error registering secfs\n"); 517f4dc3778SDmitry Kasatkin return error; 51866dbc325SMimi Zohar } 51915647eb3SDmitry Kasatkin 52015647eb3SDmitry Kasatkin return 0; 52166dbc325SMimi Zohar } 52266dbc325SMimi Zohar 52366dbc325SMimi Zohar /* 52466dbc325SMimi Zohar * evm_display_config - list the EVM protected security extended attributes 52566dbc325SMimi Zohar */ 52666dbc325SMimi Zohar static int __init evm_display_config(void) 52766dbc325SMimi Zohar { 52866dbc325SMimi Zohar char **xattrname; 52966dbc325SMimi Zohar 53066dbc325SMimi Zohar for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) 53120ee451fSJoe Perches pr_info("%s\n", *xattrname); 53266dbc325SMimi Zohar return 0; 53366dbc325SMimi Zohar } 53466dbc325SMimi Zohar 53566dbc325SMimi Zohar pure_initcall(evm_display_config); 53666dbc325SMimi Zohar late_initcall(init_evm); 53766dbc325SMimi Zohar 53866dbc325SMimi Zohar MODULE_DESCRIPTION("Extended Verification Module"); 53966dbc325SMimi Zohar MODULE_LICENSE("GPL"); 540