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