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