18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011 IBM Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author:
68c2ecf20Sopenharmony_ci * Mimi Zohar <zohar@us.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/file.h>
108c2ecf20Sopenharmony_ci#include <linux/fs.h>
118c2ecf20Sopenharmony_ci#include <linux/xattr.h>
128c2ecf20Sopenharmony_ci#include <linux/magic.h>
138c2ecf20Sopenharmony_ci#include <linux/ima.h>
148c2ecf20Sopenharmony_ci#include <linux/evm.h>
158c2ecf20Sopenharmony_ci#include <keys/system_keyring.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "ima.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic int __init default_appraise_setup(char *str)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
228c2ecf20Sopenharmony_ci	bool sb_state = arch_ima_get_secureboot();
238c2ecf20Sopenharmony_ci	int appraisal_state = ima_appraise;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if (strncmp(str, "off", 3) == 0)
268c2ecf20Sopenharmony_ci		appraisal_state = 0;
278c2ecf20Sopenharmony_ci	else if (strncmp(str, "log", 3) == 0)
288c2ecf20Sopenharmony_ci		appraisal_state = IMA_APPRAISE_LOG;
298c2ecf20Sopenharmony_ci	else if (strncmp(str, "fix", 3) == 0)
308c2ecf20Sopenharmony_ci		appraisal_state = IMA_APPRAISE_FIX;
318c2ecf20Sopenharmony_ci	else if (strncmp(str, "enforce", 7) == 0)
328c2ecf20Sopenharmony_ci		appraisal_state = IMA_APPRAISE_ENFORCE;
338c2ecf20Sopenharmony_ci	else
348c2ecf20Sopenharmony_ci		pr_err("invalid \"%s\" appraise option", str);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* If appraisal state was changed, but secure boot is enabled,
378c2ecf20Sopenharmony_ci	 * keep its default */
388c2ecf20Sopenharmony_ci	if (sb_state) {
398c2ecf20Sopenharmony_ci		if (!(appraisal_state & IMA_APPRAISE_ENFORCE))
408c2ecf20Sopenharmony_ci			pr_info("Secure boot enabled: ignoring ima_appraise=%s option",
418c2ecf20Sopenharmony_ci				str);
428c2ecf20Sopenharmony_ci	} else {
438c2ecf20Sopenharmony_ci		ima_appraise = appraisal_state;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci#endif
468c2ecf20Sopenharmony_ci	return 1;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci__setup("ima_appraise=", default_appraise_setup);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/*
528c2ecf20Sopenharmony_ci * is_ima_appraise_enabled - return appraise status
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * Only return enabled, if not in ima_appraise="fix" or "log" modes.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_cibool is_ima_appraise_enabled(void)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return ima_appraise & IMA_APPRAISE_ENFORCE;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * ima_must_appraise - set appraise flag
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * Return 1 to appraise or hash
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ciint ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	u32 secid;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (!ima_appraise)
718c2ecf20Sopenharmony_ci		return 0;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	security_task_getsecid(current, &secid);
748c2ecf20Sopenharmony_ci	return ima_match_policy(inode, current_cred(), secid, func, mask,
758c2ecf20Sopenharmony_ci				IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int ima_fix_xattr(struct dentry *dentry,
798c2ecf20Sopenharmony_ci			 struct integrity_iint_cache *iint)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	int rc, offset;
828c2ecf20Sopenharmony_ci	u8 algo = iint->ima_hash->algo;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (algo <= HASH_ALGO_SHA1) {
858c2ecf20Sopenharmony_ci		offset = 1;
868c2ecf20Sopenharmony_ci		iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
878c2ecf20Sopenharmony_ci	} else {
888c2ecf20Sopenharmony_ci		offset = 0;
898c2ecf20Sopenharmony_ci		iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
908c2ecf20Sopenharmony_ci		iint->ima_hash->xattr.ng.algo = algo;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci	rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
938c2ecf20Sopenharmony_ci				   &iint->ima_hash->xattr.data[offset],
948c2ecf20Sopenharmony_ci				   (sizeof(iint->ima_hash->xattr) - offset) +
958c2ecf20Sopenharmony_ci				   iint->ima_hash->length, 0);
968c2ecf20Sopenharmony_ci	return rc;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* Return specific func appraised cached result */
1008c2ecf20Sopenharmony_cienum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
1018c2ecf20Sopenharmony_ci					   enum ima_hooks func)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	switch (func) {
1048c2ecf20Sopenharmony_ci	case MMAP_CHECK:
1058c2ecf20Sopenharmony_ci		return iint->ima_mmap_status;
1068c2ecf20Sopenharmony_ci	case BPRM_CHECK:
1078c2ecf20Sopenharmony_ci		return iint->ima_bprm_status;
1088c2ecf20Sopenharmony_ci	case CREDS_CHECK:
1098c2ecf20Sopenharmony_ci		return iint->ima_creds_status;
1108c2ecf20Sopenharmony_ci	case FILE_CHECK:
1118c2ecf20Sopenharmony_ci	case POST_SETATTR:
1128c2ecf20Sopenharmony_ci		return iint->ima_file_status;
1138c2ecf20Sopenharmony_ci	case MODULE_CHECK ... MAX_CHECK - 1:
1148c2ecf20Sopenharmony_ci	default:
1158c2ecf20Sopenharmony_ci		return iint->ima_read_status;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void ima_set_cache_status(struct integrity_iint_cache *iint,
1208c2ecf20Sopenharmony_ci				 enum ima_hooks func,
1218c2ecf20Sopenharmony_ci				 enum integrity_status status)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	switch (func) {
1248c2ecf20Sopenharmony_ci	case MMAP_CHECK:
1258c2ecf20Sopenharmony_ci		iint->ima_mmap_status = status;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case BPRM_CHECK:
1288c2ecf20Sopenharmony_ci		iint->ima_bprm_status = status;
1298c2ecf20Sopenharmony_ci		break;
1308c2ecf20Sopenharmony_ci	case CREDS_CHECK:
1318c2ecf20Sopenharmony_ci		iint->ima_creds_status = status;
1328c2ecf20Sopenharmony_ci		break;
1338c2ecf20Sopenharmony_ci	case FILE_CHECK:
1348c2ecf20Sopenharmony_ci	case POST_SETATTR:
1358c2ecf20Sopenharmony_ci		iint->ima_file_status = status;
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci	case MODULE_CHECK ... MAX_CHECK - 1:
1388c2ecf20Sopenharmony_ci	default:
1398c2ecf20Sopenharmony_ci		iint->ima_read_status = status;
1408c2ecf20Sopenharmony_ci		break;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void ima_cache_flags(struct integrity_iint_cache *iint,
1458c2ecf20Sopenharmony_ci			     enum ima_hooks func)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	switch (func) {
1488c2ecf20Sopenharmony_ci	case MMAP_CHECK:
1498c2ecf20Sopenharmony_ci		iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
1508c2ecf20Sopenharmony_ci		break;
1518c2ecf20Sopenharmony_ci	case BPRM_CHECK:
1528c2ecf20Sopenharmony_ci		iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
1538c2ecf20Sopenharmony_ci		break;
1548c2ecf20Sopenharmony_ci	case CREDS_CHECK:
1558c2ecf20Sopenharmony_ci		iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
1568c2ecf20Sopenharmony_ci		break;
1578c2ecf20Sopenharmony_ci	case FILE_CHECK:
1588c2ecf20Sopenharmony_ci	case POST_SETATTR:
1598c2ecf20Sopenharmony_ci		iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	case MODULE_CHECK ... MAX_CHECK - 1:
1628c2ecf20Sopenharmony_ci	default:
1638c2ecf20Sopenharmony_ci		iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
1648c2ecf20Sopenharmony_ci		break;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cienum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
1698c2ecf20Sopenharmony_ci				 int xattr_len)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct signature_v2_hdr *sig;
1728c2ecf20Sopenharmony_ci	enum hash_algo ret;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (!xattr_value || xattr_len < 2)
1758c2ecf20Sopenharmony_ci		/* return default hash algo */
1768c2ecf20Sopenharmony_ci		return ima_hash_algo;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	switch (xattr_value->type) {
1798c2ecf20Sopenharmony_ci	case EVM_IMA_XATTR_DIGSIG:
1808c2ecf20Sopenharmony_ci		sig = (typeof(sig))xattr_value;
1818c2ecf20Sopenharmony_ci		if (sig->version != 2 || xattr_len <= sizeof(*sig))
1828c2ecf20Sopenharmony_ci			return ima_hash_algo;
1838c2ecf20Sopenharmony_ci		return sig->hash_algo;
1848c2ecf20Sopenharmony_ci		break;
1858c2ecf20Sopenharmony_ci	case IMA_XATTR_DIGEST_NG:
1868c2ecf20Sopenharmony_ci		/* first byte contains algorithm id */
1878c2ecf20Sopenharmony_ci		ret = xattr_value->data[0];
1888c2ecf20Sopenharmony_ci		if (ret < HASH_ALGO__LAST)
1898c2ecf20Sopenharmony_ci			return ret;
1908c2ecf20Sopenharmony_ci		break;
1918c2ecf20Sopenharmony_ci	case IMA_XATTR_DIGEST:
1928c2ecf20Sopenharmony_ci		/* this is for backward compatibility */
1938c2ecf20Sopenharmony_ci		if (xattr_len == 21) {
1948c2ecf20Sopenharmony_ci			unsigned int zero = 0;
1958c2ecf20Sopenharmony_ci			if (!memcmp(&xattr_value->data[16], &zero, 4))
1968c2ecf20Sopenharmony_ci				return HASH_ALGO_MD5;
1978c2ecf20Sopenharmony_ci			else
1988c2ecf20Sopenharmony_ci				return HASH_ALGO_SHA1;
1998c2ecf20Sopenharmony_ci		} else if (xattr_len == 17)
2008c2ecf20Sopenharmony_ci			return HASH_ALGO_MD5;
2018c2ecf20Sopenharmony_ci		break;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* return default hash algo */
2058c2ecf20Sopenharmony_ci	return ima_hash_algo;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ciint ima_read_xattr(struct dentry *dentry,
2098c2ecf20Sopenharmony_ci		   struct evm_ima_xattr_data **xattr_value)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	ssize_t ret;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
2148c2ecf20Sopenharmony_ci				 0, GFP_NOFS);
2158c2ecf20Sopenharmony_ci	if (ret == -EOPNOTSUPP)
2168c2ecf20Sopenharmony_ci		ret = 0;
2178c2ecf20Sopenharmony_ci	return ret;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/*
2218c2ecf20Sopenharmony_ci * xattr_verify - verify xattr digest or signature
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Verify whether the hash or signature matches the file contents.
2248c2ecf20Sopenharmony_ci *
2258c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise.
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_cistatic int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
2288c2ecf20Sopenharmony_ci			struct evm_ima_xattr_data *xattr_value, int xattr_len,
2298c2ecf20Sopenharmony_ci			enum integrity_status *status, const char **cause)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	int rc = -EINVAL, hash_start = 0;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	switch (xattr_value->type) {
2348c2ecf20Sopenharmony_ci	case IMA_XATTR_DIGEST_NG:
2358c2ecf20Sopenharmony_ci		/* first byte contains algorithm id */
2368c2ecf20Sopenharmony_ci		hash_start = 1;
2378c2ecf20Sopenharmony_ci		fallthrough;
2388c2ecf20Sopenharmony_ci	case IMA_XATTR_DIGEST:
2398c2ecf20Sopenharmony_ci		if (iint->flags & IMA_DIGSIG_REQUIRED) {
2408c2ecf20Sopenharmony_ci			*cause = "IMA-signature-required";
2418c2ecf20Sopenharmony_ci			*status = INTEGRITY_FAIL;
2428c2ecf20Sopenharmony_ci			break;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
2458c2ecf20Sopenharmony_ci		if (xattr_len - sizeof(xattr_value->type) - hash_start >=
2468c2ecf20Sopenharmony_ci				iint->ima_hash->length)
2478c2ecf20Sopenharmony_ci			/*
2488c2ecf20Sopenharmony_ci			 * xattr length may be longer. md5 hash in previous
2498c2ecf20Sopenharmony_ci			 * version occupied 20 bytes in xattr, instead of 16
2508c2ecf20Sopenharmony_ci			 */
2518c2ecf20Sopenharmony_ci			rc = memcmp(&xattr_value->data[hash_start],
2528c2ecf20Sopenharmony_ci				    iint->ima_hash->digest,
2538c2ecf20Sopenharmony_ci				    iint->ima_hash->length);
2548c2ecf20Sopenharmony_ci		else
2558c2ecf20Sopenharmony_ci			rc = -EINVAL;
2568c2ecf20Sopenharmony_ci		if (rc) {
2578c2ecf20Sopenharmony_ci			*cause = "invalid-hash";
2588c2ecf20Sopenharmony_ci			*status = INTEGRITY_FAIL;
2598c2ecf20Sopenharmony_ci			break;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci		*status = INTEGRITY_PASS;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case EVM_IMA_XATTR_DIGSIG:
2648c2ecf20Sopenharmony_ci		set_bit(IMA_DIGSIG, &iint->atomic_flags);
2658c2ecf20Sopenharmony_ci		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
2668c2ecf20Sopenharmony_ci					     (const char *)xattr_value,
2678c2ecf20Sopenharmony_ci					     xattr_len,
2688c2ecf20Sopenharmony_ci					     iint->ima_hash->digest,
2698c2ecf20Sopenharmony_ci					     iint->ima_hash->length);
2708c2ecf20Sopenharmony_ci		if (rc == -EOPNOTSUPP) {
2718c2ecf20Sopenharmony_ci			*status = INTEGRITY_UNKNOWN;
2728c2ecf20Sopenharmony_ci			break;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
2758c2ecf20Sopenharmony_ci		    func == KEXEC_KERNEL_CHECK)
2768c2ecf20Sopenharmony_ci			rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
2778c2ecf20Sopenharmony_ci						     (const char *)xattr_value,
2788c2ecf20Sopenharmony_ci						     xattr_len,
2798c2ecf20Sopenharmony_ci						     iint->ima_hash->digest,
2808c2ecf20Sopenharmony_ci						     iint->ima_hash->length);
2818c2ecf20Sopenharmony_ci		if (rc) {
2828c2ecf20Sopenharmony_ci			*cause = "invalid-signature";
2838c2ecf20Sopenharmony_ci			*status = INTEGRITY_FAIL;
2848c2ecf20Sopenharmony_ci		} else {
2858c2ecf20Sopenharmony_ci			*status = INTEGRITY_PASS;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	default:
2898c2ecf20Sopenharmony_ci		*status = INTEGRITY_UNKNOWN;
2908c2ecf20Sopenharmony_ci		*cause = "unknown-ima-data";
2918c2ecf20Sopenharmony_ci		break;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return rc;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/*
2988c2ecf20Sopenharmony_ci * modsig_verify - verify modsig signature
2998c2ecf20Sopenharmony_ci *
3008c2ecf20Sopenharmony_ci * Verify whether the signature matches the file contents.
3018c2ecf20Sopenharmony_ci *
3028c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise.
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistatic int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
3058c2ecf20Sopenharmony_ci			 enum integrity_status *status, const char **cause)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int rc;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
3108c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
3118c2ecf20Sopenharmony_ci	    func == KEXEC_KERNEL_CHECK)
3128c2ecf20Sopenharmony_ci		rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM,
3138c2ecf20Sopenharmony_ci					     modsig);
3148c2ecf20Sopenharmony_ci	if (rc) {
3158c2ecf20Sopenharmony_ci		*cause = "invalid-signature";
3168c2ecf20Sopenharmony_ci		*status = INTEGRITY_FAIL;
3178c2ecf20Sopenharmony_ci	} else {
3188c2ecf20Sopenharmony_ci		*status = INTEGRITY_PASS;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return rc;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/*
3258c2ecf20Sopenharmony_ci * ima_check_blacklist - determine if the binary is blacklisted.
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * Add the hash of the blacklisted binary to the measurement list, based
3288c2ecf20Sopenharmony_ci * on policy.
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * Returns -EPERM if the hash is blacklisted.
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_ciint ima_check_blacklist(struct integrity_iint_cache *iint,
3338c2ecf20Sopenharmony_ci			const struct modsig *modsig, int pcr)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	enum hash_algo hash_algo;
3368c2ecf20Sopenharmony_ci	const u8 *digest = NULL;
3378c2ecf20Sopenharmony_ci	u32 digestsize = 0;
3388c2ecf20Sopenharmony_ci	int rc = 0;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (!(iint->flags & IMA_CHECK_BLACKLIST))
3418c2ecf20Sopenharmony_ci		return 0;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (iint->flags & IMA_MODSIG_ALLOWED && modsig) {
3448c2ecf20Sopenharmony_ci		ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		rc = is_binary_blacklisted(digest, digestsize);
3478c2ecf20Sopenharmony_ci		if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
3488c2ecf20Sopenharmony_ci			process_buffer_measurement(NULL, digest, digestsize,
3498c2ecf20Sopenharmony_ci						   "blacklisted-hash", NONE,
3508c2ecf20Sopenharmony_ci						   pcr, NULL);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return rc;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci/*
3578c2ecf20Sopenharmony_ci * ima_appraise_measurement - appraise file measurement
3588c2ecf20Sopenharmony_ci *
3598c2ecf20Sopenharmony_ci * Call evm_verifyxattr() to verify the integrity of 'security.ima'.
3608c2ecf20Sopenharmony_ci * Assuming success, compare the xattr hash with the collected measurement.
3618c2ecf20Sopenharmony_ci *
3628c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise
3638c2ecf20Sopenharmony_ci */
3648c2ecf20Sopenharmony_ciint ima_appraise_measurement(enum ima_hooks func,
3658c2ecf20Sopenharmony_ci			     struct integrity_iint_cache *iint,
3668c2ecf20Sopenharmony_ci			     struct file *file, const unsigned char *filename,
3678c2ecf20Sopenharmony_ci			     struct evm_ima_xattr_data *xattr_value,
3688c2ecf20Sopenharmony_ci			     int xattr_len, const struct modsig *modsig)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	static const char op[] = "appraise_data";
3718c2ecf20Sopenharmony_ci	const char *cause = "unknown";
3728c2ecf20Sopenharmony_ci	struct dentry *dentry = file_dentry(file);
3738c2ecf20Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
3748c2ecf20Sopenharmony_ci	enum integrity_status status = INTEGRITY_UNKNOWN;
3758c2ecf20Sopenharmony_ci	int rc = xattr_len;
3768c2ecf20Sopenharmony_ci	bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* If not appraising a modsig, we need an xattr. */
3798c2ecf20Sopenharmony_ci	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
3808c2ecf20Sopenharmony_ci		return INTEGRITY_UNKNOWN;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* If reading the xattr failed and there's no modsig, error out. */
3838c2ecf20Sopenharmony_ci	if (rc <= 0 && !try_modsig) {
3848c2ecf20Sopenharmony_ci		if (rc && rc != -ENODATA)
3858c2ecf20Sopenharmony_ci			goto out;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		cause = iint->flags & IMA_DIGSIG_REQUIRED ?
3888c2ecf20Sopenharmony_ci				"IMA-signature-required" : "missing-hash";
3898c2ecf20Sopenharmony_ci		status = INTEGRITY_NOLABEL;
3908c2ecf20Sopenharmony_ci		if (file->f_mode & FMODE_CREATED)
3918c2ecf20Sopenharmony_ci			iint->flags |= IMA_NEW_FILE;
3928c2ecf20Sopenharmony_ci		if ((iint->flags & IMA_NEW_FILE) &&
3938c2ecf20Sopenharmony_ci		    (!(iint->flags & IMA_DIGSIG_REQUIRED) ||
3948c2ecf20Sopenharmony_ci		     (inode->i_size == 0)))
3958c2ecf20Sopenharmony_ci			status = INTEGRITY_PASS;
3968c2ecf20Sopenharmony_ci		goto out;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
4008c2ecf20Sopenharmony_ci				 rc < 0 ? 0 : rc, iint);
4018c2ecf20Sopenharmony_ci	switch (status) {
4028c2ecf20Sopenharmony_ci	case INTEGRITY_PASS:
4038c2ecf20Sopenharmony_ci	case INTEGRITY_PASS_IMMUTABLE:
4048c2ecf20Sopenharmony_ci	case INTEGRITY_UNKNOWN:
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	case INTEGRITY_NOXATTRS:	/* No EVM protected xattrs. */
4078c2ecf20Sopenharmony_ci		/* It's fine not to have xattrs when using a modsig. */
4088c2ecf20Sopenharmony_ci		if (try_modsig)
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		fallthrough;
4118c2ecf20Sopenharmony_ci	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
4128c2ecf20Sopenharmony_ci		cause = "missing-HMAC";
4138c2ecf20Sopenharmony_ci		goto out;
4148c2ecf20Sopenharmony_ci	case INTEGRITY_FAIL:		/* Invalid HMAC/signature. */
4158c2ecf20Sopenharmony_ci		cause = "invalid-HMAC";
4168c2ecf20Sopenharmony_ci		goto out;
4178c2ecf20Sopenharmony_ci	default:
4188c2ecf20Sopenharmony_ci		WARN_ONCE(true, "Unexpected integrity status %d\n", status);
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (xattr_value)
4228c2ecf20Sopenharmony_ci		rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
4238c2ecf20Sopenharmony_ci				  &cause);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * If we have a modsig and either no imasig or the imasig's key isn't
4278c2ecf20Sopenharmony_ci	 * known, then try verifying the modsig.
4288c2ecf20Sopenharmony_ci	 */
4298c2ecf20Sopenharmony_ci	if (try_modsig &&
4308c2ecf20Sopenharmony_ci	    (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
4318c2ecf20Sopenharmony_ci	     rc == -ENOKEY))
4328c2ecf20Sopenharmony_ci		rc = modsig_verify(func, modsig, &status, &cause);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ciout:
4358c2ecf20Sopenharmony_ci	/*
4368c2ecf20Sopenharmony_ci	 * File signatures on some filesystems can not be properly verified.
4378c2ecf20Sopenharmony_ci	 * When such filesystems are mounted by an untrusted mounter or on a
4388c2ecf20Sopenharmony_ci	 * system not willing to accept such a risk, fail the file signature
4398c2ecf20Sopenharmony_ci	 * verification.
4408c2ecf20Sopenharmony_ci	 */
4418c2ecf20Sopenharmony_ci	if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
4428c2ecf20Sopenharmony_ci	    ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
4438c2ecf20Sopenharmony_ci	     (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
4448c2ecf20Sopenharmony_ci		status = INTEGRITY_FAIL;
4458c2ecf20Sopenharmony_ci		cause = "unverifiable-signature";
4468c2ecf20Sopenharmony_ci		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
4478c2ecf20Sopenharmony_ci				    op, cause, rc, 0);
4488c2ecf20Sopenharmony_ci	} else if (status != INTEGRITY_PASS) {
4498c2ecf20Sopenharmony_ci		/* Fix mode, but don't replace file signatures. */
4508c2ecf20Sopenharmony_ci		if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
4518c2ecf20Sopenharmony_ci		    (!xattr_value ||
4528c2ecf20Sopenharmony_ci		     xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
4538c2ecf20Sopenharmony_ci			if (!ima_fix_xattr(dentry, iint))
4548c2ecf20Sopenharmony_ci				status = INTEGRITY_PASS;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		/* Permit new files with file signatures, but without data. */
4588c2ecf20Sopenharmony_ci		if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
4598c2ecf20Sopenharmony_ci		    xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
4608c2ecf20Sopenharmony_ci			status = INTEGRITY_PASS;
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
4648c2ecf20Sopenharmony_ci				    op, cause, rc, 0);
4658c2ecf20Sopenharmony_ci	} else {
4668c2ecf20Sopenharmony_ci		ima_cache_flags(iint, func);
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	ima_set_cache_status(iint, func, status);
4708c2ecf20Sopenharmony_ci	return status;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci/*
4748c2ecf20Sopenharmony_ci * ima_update_xattr - update 'security.ima' hash value
4758c2ecf20Sopenharmony_ci */
4768c2ecf20Sopenharmony_civoid ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct dentry *dentry = file_dentry(file);
4798c2ecf20Sopenharmony_ci	int rc = 0;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* do not collect and update hash for digital signatures */
4828c2ecf20Sopenharmony_ci	if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
4838c2ecf20Sopenharmony_ci		return;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if ((iint->ima_file_status != INTEGRITY_PASS) &&
4868c2ecf20Sopenharmony_ci	    !(iint->flags & IMA_HASH))
4878c2ecf20Sopenharmony_ci		return;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL);
4908c2ecf20Sopenharmony_ci	if (rc < 0)
4918c2ecf20Sopenharmony_ci		return;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	inode_lock(file_inode(file));
4948c2ecf20Sopenharmony_ci	ima_fix_xattr(dentry, iint);
4958c2ecf20Sopenharmony_ci	inode_unlock(file_inode(file));
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/**
4998c2ecf20Sopenharmony_ci * ima_inode_post_setattr - reflect file metadata changes
5008c2ecf20Sopenharmony_ci * @dentry: pointer to the affected dentry
5018c2ecf20Sopenharmony_ci *
5028c2ecf20Sopenharmony_ci * Changes to a dentry's metadata might result in needing to appraise.
5038c2ecf20Sopenharmony_ci *
5048c2ecf20Sopenharmony_ci * This function is called from notify_change(), which expects the caller
5058c2ecf20Sopenharmony_ci * to lock the inode's i_mutex.
5068c2ecf20Sopenharmony_ci */
5078c2ecf20Sopenharmony_civoid ima_inode_post_setattr(struct dentry *dentry)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
5108c2ecf20Sopenharmony_ci	struct integrity_iint_cache *iint;
5118c2ecf20Sopenharmony_ci	int action;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
5148c2ecf20Sopenharmony_ci	    || !(inode->i_opflags & IOP_XATTR))
5158c2ecf20Sopenharmony_ci		return;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
5188c2ecf20Sopenharmony_ci	if (!action)
5198c2ecf20Sopenharmony_ci		__vfs_removexattr(dentry, XATTR_NAME_IMA);
5208c2ecf20Sopenharmony_ci	iint = integrity_iint_find(inode);
5218c2ecf20Sopenharmony_ci	if (iint) {
5228c2ecf20Sopenharmony_ci		set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
5238c2ecf20Sopenharmony_ci		if (!action)
5248c2ecf20Sopenharmony_ci			clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/*
5298c2ecf20Sopenharmony_ci * ima_protect_xattr - protect 'security.ima'
5308c2ecf20Sopenharmony_ci *
5318c2ecf20Sopenharmony_ci * Ensure that not just anyone can modify or remove 'security.ima'.
5328c2ecf20Sopenharmony_ci */
5338c2ecf20Sopenharmony_cistatic int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
5348c2ecf20Sopenharmony_ci			     const void *xattr_value, size_t xattr_value_len)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) {
5378c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
5388c2ecf20Sopenharmony_ci			return -EPERM;
5398c2ecf20Sopenharmony_ci		return 1;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	return 0;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic void ima_reset_appraise_flags(struct inode *inode, int digsig)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct integrity_iint_cache *iint;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
5498c2ecf20Sopenharmony_ci		return;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	iint = integrity_iint_find(inode);
5528c2ecf20Sopenharmony_ci	if (!iint)
5538c2ecf20Sopenharmony_ci		return;
5548c2ecf20Sopenharmony_ci	iint->measured_pcrs = 0;
5558c2ecf20Sopenharmony_ci	set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
5568c2ecf20Sopenharmony_ci	if (digsig)
5578c2ecf20Sopenharmony_ci		set_bit(IMA_DIGSIG, &iint->atomic_flags);
5588c2ecf20Sopenharmony_ci	else
5598c2ecf20Sopenharmony_ci		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ciint ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
5638c2ecf20Sopenharmony_ci		       const void *xattr_value, size_t xattr_value_len)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	const struct evm_ima_xattr_data *xvalue = xattr_value;
5668c2ecf20Sopenharmony_ci	int result;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	result = ima_protect_xattr(dentry, xattr_name, xattr_value,
5698c2ecf20Sopenharmony_ci				   xattr_value_len);
5708c2ecf20Sopenharmony_ci	if (result == 1) {
5718c2ecf20Sopenharmony_ci		if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
5728c2ecf20Sopenharmony_ci			return -EINVAL;
5738c2ecf20Sopenharmony_ci		ima_reset_appraise_flags(d_backing_inode(dentry),
5748c2ecf20Sopenharmony_ci			xvalue->type == EVM_IMA_XATTR_DIGSIG);
5758c2ecf20Sopenharmony_ci		result = 0;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci	return result;
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ciint ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	int result;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
5858c2ecf20Sopenharmony_ci	if (result == 1) {
5868c2ecf20Sopenharmony_ci		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
5878c2ecf20Sopenharmony_ci		result = 0;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	return result;
5908c2ecf20Sopenharmony_ci}
591