xref: /openbmc/linux/security/integrity/ima/ima_appraise.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22fe5d6deSMimi Zohar /*
32fe5d6deSMimi Zohar  * Copyright (C) 2011 IBM Corporation
42fe5d6deSMimi Zohar  *
52fe5d6deSMimi Zohar  * Author:
62fe5d6deSMimi Zohar  * Mimi Zohar <zohar@us.ibm.com>
72fe5d6deSMimi Zohar  */
8b000d5cbSArd Biesheuvel #include <linux/module.h>
9876979c9SPaul Gortmaker #include <linux/init.h>
102fe5d6deSMimi Zohar #include <linux/file.h>
112fe5d6deSMimi Zohar #include <linux/fs.h>
122fe5d6deSMimi Zohar #include <linux/xattr.h>
132fe5d6deSMimi Zohar #include <linux/magic.h>
142fe5d6deSMimi Zohar #include <linux/ima.h>
152fe5d6deSMimi Zohar #include <linux/evm.h>
16398c42e2SMimi Zohar #include <linux/fsverity.h>
17273df864SNayna Jain #include <keys/system_keyring.h>
18398c42e2SMimi Zohar #include <uapi/linux/fsverity.h>
192fe5d6deSMimi Zohar 
202fe5d6deSMimi Zohar #include "ima.h"
212fe5d6deSMimi Zohar 
22e1f5e01fSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
23b000d5cbSArd Biesheuvel static char *ima_appraise_cmdline_default __initdata;
24b000d5cbSArd Biesheuvel core_param(ima_appraise, ima_appraise_cmdline_default, charp, 0);
25b000d5cbSArd Biesheuvel 
ima_appraise_parse_cmdline(void)26b000d5cbSArd Biesheuvel void __init ima_appraise_parse_cmdline(void)
27b000d5cbSArd Biesheuvel {
28b000d5cbSArd Biesheuvel 	const char *str = ima_appraise_cmdline_default;
29e4d7e2dfSBruno Meneguele 	bool sb_state = arch_ima_get_secureboot();
30e4d7e2dfSBruno Meneguele 	int appraisal_state = ima_appraise;
31311aa6aaSBruno Meneguele 
32b000d5cbSArd Biesheuvel 	if (!str)
33b000d5cbSArd Biesheuvel 		return;
34b000d5cbSArd Biesheuvel 
352fe5d6deSMimi Zohar 	if (strncmp(str, "off", 3) == 0)
36e4d7e2dfSBruno Meneguele 		appraisal_state = 0;
372faa6ef3SDmitry Kasatkin 	else if (strncmp(str, "log", 3) == 0)
38e4d7e2dfSBruno Meneguele 		appraisal_state = IMA_APPRAISE_LOG;
392fe5d6deSMimi Zohar 	else if (strncmp(str, "fix", 3) == 0)
40e4d7e2dfSBruno Meneguele 		appraisal_state = IMA_APPRAISE_FIX;
414afb28abSBruno Meneguele 	else if (strncmp(str, "enforce", 7) == 0)
42e4d7e2dfSBruno Meneguele 		appraisal_state = IMA_APPRAISE_ENFORCE;
437fe2bb7eSBruno Meneguele 	else
447fe2bb7eSBruno Meneguele 		pr_err("invalid \"%s\" appraise option", str);
45e4d7e2dfSBruno Meneguele 
46e4d7e2dfSBruno Meneguele 	/* If appraisal state was changed, but secure boot is enabled,
47e4d7e2dfSBruno Meneguele 	 * keep its default */
48e4d7e2dfSBruno Meneguele 	if (sb_state) {
49e4d7e2dfSBruno Meneguele 		if (!(appraisal_state & IMA_APPRAISE_ENFORCE))
50e4d7e2dfSBruno Meneguele 			pr_info("Secure boot enabled: ignoring ima_appraise=%s option",
51e4d7e2dfSBruno Meneguele 				str);
52e4d7e2dfSBruno Meneguele 	} else {
53e4d7e2dfSBruno Meneguele 		ima_appraise = appraisal_state;
54e4d7e2dfSBruno Meneguele 	}
552fe5d6deSMimi Zohar }
56b000d5cbSArd Biesheuvel #endif
572fe5d6deSMimi Zohar 
582fe5d6deSMimi Zohar /*
596f6723e2SMimi Zohar  * is_ima_appraise_enabled - return appraise status
606f6723e2SMimi Zohar  *
616f6723e2SMimi Zohar  * Only return enabled, if not in ima_appraise="fix" or "log" modes.
626f6723e2SMimi Zohar  */
is_ima_appraise_enabled(void)636f6723e2SMimi Zohar bool is_ima_appraise_enabled(void)
646f6723e2SMimi Zohar {
65e5729f86SThiago Jung Bauermann 	return ima_appraise & IMA_APPRAISE_ENFORCE;
666f6723e2SMimi Zohar }
676f6723e2SMimi Zohar 
686f6723e2SMimi Zohar /*
692fe5d6deSMimi Zohar  * ima_must_appraise - set appraise flag
702fe5d6deSMimi Zohar  *
71da1b0029SMimi Zohar  * Return 1 to appraise or hash
722fe5d6deSMimi Zohar  */
ima_must_appraise(struct mnt_idmap * idmap,struct inode * inode,int mask,enum ima_hooks func)7339f60c1cSChristian Brauner int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
74a2d2329eSChristian Brauner 		      int mask, enum ima_hooks func)
752fe5d6deSMimi Zohar {
76d906c10dSMatthew Garrett 	u32 secid;
77d906c10dSMatthew Garrett 
7807f6a794SMimi Zohar 	if (!ima_appraise)
792fe5d6deSMimi Zohar 		return 0;
8007f6a794SMimi Zohar 
816326948fSPaul Moore 	security_current_getsecid_subj(&secid);
8239f60c1cSChristian Brauner 	return ima_match_policy(idmap, inode, current_cred(), secid,
831624dc00STHOBY Simon 				func, mask, IMA_APPRAISE | IMA_HASH, NULL,
841624dc00STHOBY Simon 				NULL, NULL, NULL);
852fe5d6deSMimi Zohar }
862fe5d6deSMimi Zohar 
ima_fix_xattr(struct dentry * dentry,struct integrity_iint_cache * iint)87def3e8b9SDmitry Kasatkin static int ima_fix_xattr(struct dentry *dentry,
882fe5d6deSMimi Zohar 			 struct integrity_iint_cache *iint)
892fe5d6deSMimi Zohar {
903ea7a560SDmitry Kasatkin 	int rc, offset;
913ea7a560SDmitry Kasatkin 	u8 algo = iint->ima_hash->algo;
923ea7a560SDmitry Kasatkin 
933ea7a560SDmitry Kasatkin 	if (algo <= HASH_ALGO_SHA1) {
943ea7a560SDmitry Kasatkin 		offset = 1;
953ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
963ea7a560SDmitry Kasatkin 	} else {
973ea7a560SDmitry Kasatkin 		offset = 0;
983ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
993ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.ng.algo = algo;
1003ea7a560SDmitry Kasatkin 	}
10139f60c1cSChristian Brauner 	rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_IMA,
1023ea7a560SDmitry Kasatkin 				   &iint->ima_hash->xattr.data[offset],
1033ea7a560SDmitry Kasatkin 				   (sizeof(iint->ima_hash->xattr) - offset) +
1043ea7a560SDmitry Kasatkin 				   iint->ima_hash->length, 0);
1053ea7a560SDmitry Kasatkin 	return rc;
1062fe5d6deSMimi Zohar }
1072fe5d6deSMimi Zohar 
108d79d72e0SMimi Zohar /* Return specific func appraised cached result */
ima_get_cache_status(struct integrity_iint_cache * iint,enum ima_hooks func)109d79d72e0SMimi Zohar enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
1104ad87a3dSMimi Zohar 					   enum ima_hooks func)
111d79d72e0SMimi Zohar {
112d79d72e0SMimi Zohar 	switch (func) {
113d79d72e0SMimi Zohar 	case MMAP_CHECK:
1144958db32SRoberto Sassu 	case MMAP_CHECK_REQPROT:
115d79d72e0SMimi Zohar 		return iint->ima_mmap_status;
116d79d72e0SMimi Zohar 	case BPRM_CHECK:
117d79d72e0SMimi Zohar 		return iint->ima_bprm_status;
118d906c10dSMatthew Garrett 	case CREDS_CHECK:
119d906c10dSMatthew Garrett 		return iint->ima_creds_status;
120d79d72e0SMimi Zohar 	case FILE_CHECK:
121c6af8efeSMimi Zohar 	case POST_SETATTR:
122d79d72e0SMimi Zohar 		return iint->ima_file_status;
123c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
124c6af8efeSMimi Zohar 	default:
125c6af8efeSMimi Zohar 		return iint->ima_read_status;
126d79d72e0SMimi Zohar 	}
127d79d72e0SMimi Zohar }
128d79d72e0SMimi Zohar 
ima_set_cache_status(struct integrity_iint_cache * iint,enum ima_hooks func,enum integrity_status status)129d79d72e0SMimi Zohar static void ima_set_cache_status(struct integrity_iint_cache *iint,
1304ad87a3dSMimi Zohar 				 enum ima_hooks func,
1314ad87a3dSMimi Zohar 				 enum integrity_status status)
132d79d72e0SMimi Zohar {
133d79d72e0SMimi Zohar 	switch (func) {
134d79d72e0SMimi Zohar 	case MMAP_CHECK:
1354958db32SRoberto Sassu 	case MMAP_CHECK_REQPROT:
136d79d72e0SMimi Zohar 		iint->ima_mmap_status = status;
137d79d72e0SMimi Zohar 		break;
138d79d72e0SMimi Zohar 	case BPRM_CHECK:
139d79d72e0SMimi Zohar 		iint->ima_bprm_status = status;
140d79d72e0SMimi Zohar 		break;
141d906c10dSMatthew Garrett 	case CREDS_CHECK:
142d906c10dSMatthew Garrett 		iint->ima_creds_status = status;
14309186e50SGustavo A. R. Silva 		break;
144d79d72e0SMimi Zohar 	case FILE_CHECK:
145c6af8efeSMimi Zohar 	case POST_SETATTR:
146d79d72e0SMimi Zohar 		iint->ima_file_status = status;
147c6af8efeSMimi Zohar 		break;
148c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
149c6af8efeSMimi Zohar 	default:
150c6af8efeSMimi Zohar 		iint->ima_read_status = status;
151c6af8efeSMimi Zohar 		break;
152d79d72e0SMimi Zohar 	}
153d79d72e0SMimi Zohar }
154d79d72e0SMimi Zohar 
ima_cache_flags(struct integrity_iint_cache * iint,enum ima_hooks func)1554ad87a3dSMimi Zohar static void ima_cache_flags(struct integrity_iint_cache *iint,
1564ad87a3dSMimi Zohar 			     enum ima_hooks func)
157d79d72e0SMimi Zohar {
158d79d72e0SMimi Zohar 	switch (func) {
159d79d72e0SMimi Zohar 	case MMAP_CHECK:
1604958db32SRoberto Sassu 	case MMAP_CHECK_REQPROT:
161d79d72e0SMimi Zohar 		iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
162d79d72e0SMimi Zohar 		break;
163d79d72e0SMimi Zohar 	case BPRM_CHECK:
164d79d72e0SMimi Zohar 		iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
165d79d72e0SMimi Zohar 		break;
166d906c10dSMatthew Garrett 	case CREDS_CHECK:
167d906c10dSMatthew Garrett 		iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
168d906c10dSMatthew Garrett 		break;
169d79d72e0SMimi Zohar 	case FILE_CHECK:
170c6af8efeSMimi Zohar 	case POST_SETATTR:
171d79d72e0SMimi Zohar 		iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
172c6af8efeSMimi Zohar 		break;
173c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
174c6af8efeSMimi Zohar 	default:
175c6af8efeSMimi Zohar 		iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
176c6af8efeSMimi Zohar 		break;
177d79d72e0SMimi Zohar 	}
178d79d72e0SMimi Zohar }
179d79d72e0SMimi Zohar 
ima_get_hash_algo(const struct evm_ima_xattr_data * xattr_value,int xattr_len)18050f742ddSTHOBY Simon enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
1811525b06dSDmitry Kasatkin 				 int xattr_len)
182d3634d0fSDmitry Kasatkin {
183d3634d0fSDmitry Kasatkin 	struct signature_v2_hdr *sig;
184b4bfec7fSSeth Forshee 	enum hash_algo ret;
185d3634d0fSDmitry Kasatkin 
1863ea7a560SDmitry Kasatkin 	if (!xattr_value || xattr_len < 2)
1871525b06dSDmitry Kasatkin 		/* return default hash algo */
1881525b06dSDmitry Kasatkin 		return ima_hash_algo;
189d3634d0fSDmitry Kasatkin 
1903ea7a560SDmitry Kasatkin 	switch (xattr_value->type) {
191398c42e2SMimi Zohar 	case IMA_VERITY_DIGSIG:
192398c42e2SMimi Zohar 		sig = (typeof(sig))xattr_value;
193398c42e2SMimi Zohar 		if (sig->version != 3 || xattr_len <= sizeof(*sig) ||
194398c42e2SMimi Zohar 		    sig->hash_algo >= HASH_ALGO__LAST)
195398c42e2SMimi Zohar 			return ima_hash_algo;
196398c42e2SMimi Zohar 		return sig->hash_algo;
1973ea7a560SDmitry Kasatkin 	case EVM_IMA_XATTR_DIGSIG:
1983ea7a560SDmitry Kasatkin 		sig = (typeof(sig))xattr_value;
199cb181da1STHOBY Simon 		if (sig->version != 2 || xattr_len <= sizeof(*sig)
200cb181da1STHOBY Simon 		    || sig->hash_algo >= HASH_ALGO__LAST)
2011525b06dSDmitry Kasatkin 			return ima_hash_algo;
2021525b06dSDmitry Kasatkin 		return sig->hash_algo;
2033ea7a560SDmitry Kasatkin 	case IMA_XATTR_DIGEST_NG:
204650b29dbSThiago Jung Bauermann 		/* first byte contains algorithm id */
205650b29dbSThiago Jung Bauermann 		ret = xattr_value->data[0];
206b4bfec7fSSeth Forshee 		if (ret < HASH_ALGO__LAST)
207b4bfec7fSSeth Forshee 			return ret;
2083ea7a560SDmitry Kasatkin 		break;
2093ea7a560SDmitry Kasatkin 	case IMA_XATTR_DIGEST:
2103ea7a560SDmitry Kasatkin 		/* this is for backward compatibility */
2113ea7a560SDmitry Kasatkin 		if (xattr_len == 21) {
2123ea7a560SDmitry Kasatkin 			unsigned int zero = 0;
213650b29dbSThiago Jung Bauermann 			if (!memcmp(&xattr_value->data[16], &zero, 4))
2141525b06dSDmitry Kasatkin 				return HASH_ALGO_MD5;
2153ea7a560SDmitry Kasatkin 			else
2161525b06dSDmitry Kasatkin 				return HASH_ALGO_SHA1;
2173ea7a560SDmitry Kasatkin 		} else if (xattr_len == 17)
2181525b06dSDmitry Kasatkin 			return HASH_ALGO_MD5;
2193ea7a560SDmitry Kasatkin 		break;
2203ea7a560SDmitry Kasatkin 	}
2211525b06dSDmitry Kasatkin 
2221525b06dSDmitry Kasatkin 	/* return default hash algo */
2231525b06dSDmitry Kasatkin 	return ima_hash_algo;
224d3634d0fSDmitry Kasatkin }
225d3634d0fSDmitry Kasatkin 
ima_read_xattr(struct dentry * dentry,struct evm_ima_xattr_data ** xattr_value,int xattr_len)226d3634d0fSDmitry Kasatkin int ima_read_xattr(struct dentry *dentry,
227f6fbd8cbSPaul Moore 		   struct evm_ima_xattr_data **xattr_value, int xattr_len)
228d3634d0fSDmitry Kasatkin {
229f6fbd8cbSPaul Moore 	int ret;
230d3634d0fSDmitry Kasatkin 
2314609e1f1SChristian Brauner 	ret = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, XATTR_NAME_IMA,
232f6fbd8cbSPaul Moore 				 (char **)xattr_value, xattr_len, GFP_NOFS);
2335d6c3191SAndreas Gruenbacher 	if (ret == -EOPNOTSUPP)
2345d6c3191SAndreas Gruenbacher 		ret = 0;
2355d6c3191SAndreas Gruenbacher 	return ret;
236d3634d0fSDmitry Kasatkin }
237d3634d0fSDmitry Kasatkin 
2382fe5d6deSMimi Zohar /*
239398c42e2SMimi Zohar  * calc_file_id_hash - calculate the hash of the ima_file_id struct data
240398c42e2SMimi Zohar  * @type: xattr type [enum evm_ima_xattr_type]
241398c42e2SMimi Zohar  * @algo: hash algorithm [enum hash_algo]
242398c42e2SMimi Zohar  * @digest: pointer to the digest to be hashed
243398c42e2SMimi Zohar  * @hash: (out) pointer to the hash
244398c42e2SMimi Zohar  *
245398c42e2SMimi Zohar  * IMA signature version 3 disambiguates the data that is signed by
246398c42e2SMimi Zohar  * indirectly signing the hash of the ima_file_id structure data.
247398c42e2SMimi Zohar  *
248398c42e2SMimi Zohar  * Signing the ima_file_id struct is currently only supported for
249398c42e2SMimi Zohar  * IMA_VERITY_DIGSIG type xattrs.
250398c42e2SMimi Zohar  *
251398c42e2SMimi Zohar  * Return 0 on success, error code otherwise.
252398c42e2SMimi Zohar  */
calc_file_id_hash(enum evm_ima_xattr_type type,enum hash_algo algo,const u8 * digest,struct ima_digest_data * hash)253398c42e2SMimi Zohar static int calc_file_id_hash(enum evm_ima_xattr_type type,
254398c42e2SMimi Zohar 			     enum hash_algo algo, const u8 *digest,
255398c42e2SMimi Zohar 			     struct ima_digest_data *hash)
256398c42e2SMimi Zohar {
257398c42e2SMimi Zohar 	struct ima_file_id file_id = {
258398c42e2SMimi Zohar 		.hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo};
259398c42e2SMimi Zohar 	unsigned int unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
260398c42e2SMimi Zohar 
261398c42e2SMimi Zohar 	if (type != IMA_VERITY_DIGSIG)
262398c42e2SMimi Zohar 		return -EINVAL;
263398c42e2SMimi Zohar 
264398c42e2SMimi Zohar 	memcpy(file_id.hash, digest, hash_digest_size[algo]);
265398c42e2SMimi Zohar 
266398c42e2SMimi Zohar 	hash->algo = algo;
267398c42e2SMimi Zohar 	hash->length = hash_digest_size[algo];
268398c42e2SMimi Zohar 
269398c42e2SMimi Zohar 	return ima_calc_buffer_hash(&file_id, sizeof(file_id) - unused, hash);
270398c42e2SMimi Zohar }
271398c42e2SMimi Zohar 
272398c42e2SMimi Zohar /*
273a5fbeb61SThiago Jung Bauermann  * xattr_verify - verify xattr digest or signature
274a5fbeb61SThiago Jung Bauermann  *
275a5fbeb61SThiago Jung Bauermann  * Verify whether the hash or signature matches the file contents.
276a5fbeb61SThiago Jung Bauermann  *
277a5fbeb61SThiago Jung Bauermann  * Return 0 on success, error code otherwise.
278a5fbeb61SThiago Jung Bauermann  */
xattr_verify(enum ima_hooks func,struct integrity_iint_cache * iint,struct evm_ima_xattr_data * xattr_value,int xattr_len,enum integrity_status * status,const char ** cause)279a5fbeb61SThiago Jung Bauermann static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
280a5fbeb61SThiago Jung Bauermann 			struct evm_ima_xattr_data *xattr_value, int xattr_len,
281a5fbeb61SThiago Jung Bauermann 			enum integrity_status *status, const char **cause)
282a5fbeb61SThiago Jung Bauermann {
283398c42e2SMimi Zohar 	struct ima_max_digest_data hash;
284398c42e2SMimi Zohar 	struct signature_v2_hdr *sig;
285a5fbeb61SThiago Jung Bauermann 	int rc = -EINVAL, hash_start = 0;
286398c42e2SMimi Zohar 	int mask;
287a5fbeb61SThiago Jung Bauermann 
288a5fbeb61SThiago Jung Bauermann 	switch (xattr_value->type) {
289a5fbeb61SThiago Jung Bauermann 	case IMA_XATTR_DIGEST_NG:
290a5fbeb61SThiago Jung Bauermann 		/* first byte contains algorithm id */
291a5fbeb61SThiago Jung Bauermann 		hash_start = 1;
292df561f66SGustavo A. R. Silva 		fallthrough;
293a5fbeb61SThiago Jung Bauermann 	case IMA_XATTR_DIGEST:
2947aa5783dSRoberto Sassu 		if (*status != INTEGRITY_PASS_IMMUTABLE) {
295a5fbeb61SThiago Jung Bauermann 			if (iint->flags & IMA_DIGSIG_REQUIRED) {
296398c42e2SMimi Zohar 				if (iint->flags & IMA_VERITY_REQUIRED)
297398c42e2SMimi Zohar 					*cause = "verity-signature-required";
298398c42e2SMimi Zohar 				else
299a5fbeb61SThiago Jung Bauermann 					*cause = "IMA-signature-required";
300a5fbeb61SThiago Jung Bauermann 				*status = INTEGRITY_FAIL;
301a5fbeb61SThiago Jung Bauermann 				break;
302a5fbeb61SThiago Jung Bauermann 			}
303a5fbeb61SThiago Jung Bauermann 			clear_bit(IMA_DIGSIG, &iint->atomic_flags);
3047aa5783dSRoberto Sassu 		} else {
3057aa5783dSRoberto Sassu 			set_bit(IMA_DIGSIG, &iint->atomic_flags);
3067aa5783dSRoberto Sassu 		}
307a5fbeb61SThiago Jung Bauermann 		if (xattr_len - sizeof(xattr_value->type) - hash_start >=
308a5fbeb61SThiago Jung Bauermann 				iint->ima_hash->length)
309a5fbeb61SThiago Jung Bauermann 			/*
310a5fbeb61SThiago Jung Bauermann 			 * xattr length may be longer. md5 hash in previous
311a5fbeb61SThiago Jung Bauermann 			 * version occupied 20 bytes in xattr, instead of 16
312a5fbeb61SThiago Jung Bauermann 			 */
313a5fbeb61SThiago Jung Bauermann 			rc = memcmp(&xattr_value->data[hash_start],
314a5fbeb61SThiago Jung Bauermann 				    iint->ima_hash->digest,
315a5fbeb61SThiago Jung Bauermann 				    iint->ima_hash->length);
316a5fbeb61SThiago Jung Bauermann 		else
317a5fbeb61SThiago Jung Bauermann 			rc = -EINVAL;
318a5fbeb61SThiago Jung Bauermann 		if (rc) {
319a5fbeb61SThiago Jung Bauermann 			*cause = "invalid-hash";
320a5fbeb61SThiago Jung Bauermann 			*status = INTEGRITY_FAIL;
321a5fbeb61SThiago Jung Bauermann 			break;
322a5fbeb61SThiago Jung Bauermann 		}
323a5fbeb61SThiago Jung Bauermann 		*status = INTEGRITY_PASS;
324a5fbeb61SThiago Jung Bauermann 		break;
325a5fbeb61SThiago Jung Bauermann 	case EVM_IMA_XATTR_DIGSIG:
326a5fbeb61SThiago Jung Bauermann 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
327398c42e2SMimi Zohar 
328398c42e2SMimi Zohar 		mask = IMA_DIGSIG_REQUIRED | IMA_VERITY_REQUIRED;
329398c42e2SMimi Zohar 		if ((iint->flags & mask) == mask) {
330398c42e2SMimi Zohar 			*cause = "verity-signature-required";
331398c42e2SMimi Zohar 			*status = INTEGRITY_FAIL;
332398c42e2SMimi Zohar 			break;
333398c42e2SMimi Zohar 		}
334398c42e2SMimi Zohar 
335398c42e2SMimi Zohar 		sig = (typeof(sig))xattr_value;
336398c42e2SMimi Zohar 		if (sig->version >= 3) {
337398c42e2SMimi Zohar 			*cause = "invalid-signature-version";
338398c42e2SMimi Zohar 			*status = INTEGRITY_FAIL;
339398c42e2SMimi Zohar 			break;
340398c42e2SMimi Zohar 		}
341a5fbeb61SThiago Jung Bauermann 		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
342a5fbeb61SThiago Jung Bauermann 					     (const char *)xattr_value,
343a5fbeb61SThiago Jung Bauermann 					     xattr_len,
344a5fbeb61SThiago Jung Bauermann 					     iint->ima_hash->digest,
345a5fbeb61SThiago Jung Bauermann 					     iint->ima_hash->length);
346a5fbeb61SThiago Jung Bauermann 		if (rc == -EOPNOTSUPP) {
347a5fbeb61SThiago Jung Bauermann 			*status = INTEGRITY_UNKNOWN;
348a5fbeb61SThiago Jung Bauermann 			break;
349a5fbeb61SThiago Jung Bauermann 		}
350a5fbeb61SThiago Jung Bauermann 		if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
351a5fbeb61SThiago Jung Bauermann 		    func == KEXEC_KERNEL_CHECK)
352a5fbeb61SThiago Jung Bauermann 			rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
353a5fbeb61SThiago Jung Bauermann 						     (const char *)xattr_value,
354a5fbeb61SThiago Jung Bauermann 						     xattr_len,
355a5fbeb61SThiago Jung Bauermann 						     iint->ima_hash->digest,
356a5fbeb61SThiago Jung Bauermann 						     iint->ima_hash->length);
357a5fbeb61SThiago Jung Bauermann 		if (rc) {
358a5fbeb61SThiago Jung Bauermann 			*cause = "invalid-signature";
359a5fbeb61SThiago Jung Bauermann 			*status = INTEGRITY_FAIL;
360a5fbeb61SThiago Jung Bauermann 		} else {
361a5fbeb61SThiago Jung Bauermann 			*status = INTEGRITY_PASS;
362a5fbeb61SThiago Jung Bauermann 		}
363a5fbeb61SThiago Jung Bauermann 		break;
364398c42e2SMimi Zohar 	case IMA_VERITY_DIGSIG:
365398c42e2SMimi Zohar 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
366398c42e2SMimi Zohar 
367398c42e2SMimi Zohar 		if (iint->flags & IMA_DIGSIG_REQUIRED) {
368398c42e2SMimi Zohar 			if (!(iint->flags & IMA_VERITY_REQUIRED)) {
369398c42e2SMimi Zohar 				*cause = "IMA-signature-required";
370398c42e2SMimi Zohar 				*status = INTEGRITY_FAIL;
371398c42e2SMimi Zohar 				break;
372398c42e2SMimi Zohar 			}
373398c42e2SMimi Zohar 		}
374398c42e2SMimi Zohar 
375398c42e2SMimi Zohar 		sig = (typeof(sig))xattr_value;
376398c42e2SMimi Zohar 		if (sig->version != 3) {
377398c42e2SMimi Zohar 			*cause = "invalid-signature-version";
378398c42e2SMimi Zohar 			*status = INTEGRITY_FAIL;
379398c42e2SMimi Zohar 			break;
380398c42e2SMimi Zohar 		}
381398c42e2SMimi Zohar 
382398c42e2SMimi Zohar 		rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
383398c42e2SMimi Zohar 				       iint->ima_hash->digest, &hash.hdr);
384398c42e2SMimi Zohar 		if (rc) {
385398c42e2SMimi Zohar 			*cause = "sigv3-hashing-error";
386398c42e2SMimi Zohar 			*status = INTEGRITY_FAIL;
387398c42e2SMimi Zohar 			break;
388398c42e2SMimi Zohar 		}
389398c42e2SMimi Zohar 
390398c42e2SMimi Zohar 		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
391398c42e2SMimi Zohar 					     (const char *)xattr_value,
392398c42e2SMimi Zohar 					     xattr_len, hash.digest,
393398c42e2SMimi Zohar 					     hash.hdr.length);
394398c42e2SMimi Zohar 		if (rc) {
395398c42e2SMimi Zohar 			*cause = "invalid-verity-signature";
396398c42e2SMimi Zohar 			*status = INTEGRITY_FAIL;
397398c42e2SMimi Zohar 		} else {
398398c42e2SMimi Zohar 			*status = INTEGRITY_PASS;
399398c42e2SMimi Zohar 		}
400398c42e2SMimi Zohar 
401398c42e2SMimi Zohar 		break;
402a5fbeb61SThiago Jung Bauermann 	default:
403a5fbeb61SThiago Jung Bauermann 		*status = INTEGRITY_UNKNOWN;
404a5fbeb61SThiago Jung Bauermann 		*cause = "unknown-ima-data";
405a5fbeb61SThiago Jung Bauermann 		break;
406a5fbeb61SThiago Jung Bauermann 	}
407a5fbeb61SThiago Jung Bauermann 
408a5fbeb61SThiago Jung Bauermann 	return rc;
409a5fbeb61SThiago Jung Bauermann }
410a5fbeb61SThiago Jung Bauermann 
411a5fbeb61SThiago Jung Bauermann /*
41239b07096SThiago Jung Bauermann  * modsig_verify - verify modsig signature
41339b07096SThiago Jung Bauermann  *
41439b07096SThiago Jung Bauermann  * Verify whether the signature matches the file contents.
41539b07096SThiago Jung Bauermann  *
41639b07096SThiago Jung Bauermann  * Return 0 on success, error code otherwise.
41739b07096SThiago Jung Bauermann  */
modsig_verify(enum ima_hooks func,const struct modsig * modsig,enum integrity_status * status,const char ** cause)41839b07096SThiago Jung Bauermann static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
41939b07096SThiago Jung Bauermann 			 enum integrity_status *status, const char **cause)
42039b07096SThiago Jung Bauermann {
42139b07096SThiago Jung Bauermann 	int rc;
42239b07096SThiago Jung Bauermann 
42339b07096SThiago Jung Bauermann 	rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
42439b07096SThiago Jung Bauermann 	if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
42539b07096SThiago Jung Bauermann 	    func == KEXEC_KERNEL_CHECK)
42639b07096SThiago Jung Bauermann 		rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM,
42739b07096SThiago Jung Bauermann 					     modsig);
42839b07096SThiago Jung Bauermann 	if (rc) {
42939b07096SThiago Jung Bauermann 		*cause = "invalid-signature";
43039b07096SThiago Jung Bauermann 		*status = INTEGRITY_FAIL;
43139b07096SThiago Jung Bauermann 	} else {
43239b07096SThiago Jung Bauermann 		*status = INTEGRITY_PASS;
43339b07096SThiago Jung Bauermann 	}
43439b07096SThiago Jung Bauermann 
43539b07096SThiago Jung Bauermann 	return rc;
43639b07096SThiago Jung Bauermann }
43739b07096SThiago Jung Bauermann 
43839b07096SThiago Jung Bauermann /*
439273df864SNayna Jain  * ima_check_blacklist - determine if the binary is blacklisted.
440273df864SNayna Jain  *
441273df864SNayna Jain  * Add the hash of the blacklisted binary to the measurement list, based
442273df864SNayna Jain  * on policy.
443273df864SNayna Jain  *
444273df864SNayna Jain  * Returns -EPERM if the hash is blacklisted.
445273df864SNayna Jain  */
ima_check_blacklist(struct integrity_iint_cache * iint,const struct modsig * modsig,int pcr)446273df864SNayna Jain int ima_check_blacklist(struct integrity_iint_cache *iint,
447273df864SNayna Jain 			const struct modsig *modsig, int pcr)
448273df864SNayna Jain {
449273df864SNayna Jain 	enum hash_algo hash_algo;
450273df864SNayna Jain 	const u8 *digest = NULL;
451273df864SNayna Jain 	u32 digestsize = 0;
452273df864SNayna Jain 	int rc = 0;
453273df864SNayna Jain 
454273df864SNayna Jain 	if (!(iint->flags & IMA_CHECK_BLACKLIST))
455273df864SNayna Jain 		return 0;
456273df864SNayna Jain 
457273df864SNayna Jain 	if (iint->flags & IMA_MODSIG_ALLOWED && modsig) {
458273df864SNayna Jain 		ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize);
459273df864SNayna Jain 
460273df864SNayna Jain 		rc = is_binary_blacklisted(digest, digestsize);
461*f20765fdSEric Snowberg 	} else if (iint->flags & IMA_DIGSIG_REQUIRED && iint->ima_hash)
462*f20765fdSEric Snowberg 		rc = is_binary_blacklisted(iint->ima_hash->digest, iint->ima_hash->length);
463*f20765fdSEric Snowberg 
464273df864SNayna Jain 	if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
46539f60c1cSChristian Brauner 		process_buffer_measurement(&nop_mnt_idmap, NULL, digest, digestsize,
466273df864SNayna Jain 					   "blacklisted-hash", NONE,
467ca3c9bdbSRoberto Sassu 					   pcr, NULL, false, NULL, 0);
468273df864SNayna Jain 
469273df864SNayna Jain 	return rc;
470273df864SNayna Jain }
471273df864SNayna Jain 
472273df864SNayna Jain /*
4732fe5d6deSMimi Zohar  * ima_appraise_measurement - appraise file measurement
4742fe5d6deSMimi Zohar  *
4752fe5d6deSMimi Zohar  * Call evm_verifyxattr() to verify the integrity of 'security.ima'.
4762fe5d6deSMimi Zohar  * Assuming success, compare the xattr hash with the collected measurement.
4772fe5d6deSMimi Zohar  *
4782fe5d6deSMimi Zohar  * Return 0 on success, error code otherwise
4792fe5d6deSMimi Zohar  */
ima_appraise_measurement(enum ima_hooks func,struct integrity_iint_cache * iint,struct file * file,const unsigned char * filename,struct evm_ima_xattr_data * xattr_value,int xattr_len,const struct modsig * modsig)4804ad87a3dSMimi Zohar int ima_appraise_measurement(enum ima_hooks func,
4814ad87a3dSMimi Zohar 			     struct integrity_iint_cache *iint,
482d3634d0fSDmitry Kasatkin 			     struct file *file, const unsigned char *filename,
483d3634d0fSDmitry Kasatkin 			     struct evm_ima_xattr_data *xattr_value,
48439b07096SThiago Jung Bauermann 			     int xattr_len, const struct modsig *modsig)
4852fe5d6deSMimi Zohar {
48652a13284SMimi Zohar 	static const char op[] = "appraise_data";
487f5e51fa3SThiago Jung Bauermann 	const char *cause = "unknown";
488e71b9dffSMiklos Szeredi 	struct dentry *dentry = file_dentry(file);
489c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
4902fe5d6deSMimi Zohar 	enum integrity_status status = INTEGRITY_UNKNOWN;
491a5fbeb61SThiago Jung Bauermann 	int rc = xattr_len;
49239b07096SThiago Jung Bauermann 	bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
4932fe5d6deSMimi Zohar 
49439b07096SThiago Jung Bauermann 	/* If not appraising a modsig, we need an xattr. */
49539b07096SThiago Jung Bauermann 	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
4962fe5d6deSMimi Zohar 		return INTEGRITY_UNKNOWN;
4972fe5d6deSMimi Zohar 
49839b07096SThiago Jung Bauermann 	/* If reading the xattr failed and there's no modsig, error out. */
49939b07096SThiago Jung Bauermann 	if (rc <= 0 && !try_modsig) {
5002fe5d6deSMimi Zohar 		if (rc && rc != -ENODATA)
5012fe5d6deSMimi Zohar 			goto out;
5022fe5d6deSMimi Zohar 
503398c42e2SMimi Zohar 		if (iint->flags & IMA_DIGSIG_REQUIRED) {
504398c42e2SMimi Zohar 			if (iint->flags & IMA_VERITY_REQUIRED)
505398c42e2SMimi Zohar 				cause = "verity-signature-required";
506398c42e2SMimi Zohar 			else
507398c42e2SMimi Zohar 				cause = "IMA-signature-required";
508398c42e2SMimi Zohar 		} else {
509398c42e2SMimi Zohar 			cause = "missing-hash";
510398c42e2SMimi Zohar 		}
511398c42e2SMimi Zohar 
512b151d6b0SDmitry Kasatkin 		status = INTEGRITY_NOLABEL;
5136035a27bSAl Viro 		if (file->f_mode & FMODE_CREATED)
514b151d6b0SDmitry Kasatkin 			iint->flags |= IMA_NEW_FILE;
5151ac202e9SDaniel Glöckner 		if ((iint->flags & IMA_NEW_FILE) &&
516b7e27bc1SMimi Zohar 		    (!(iint->flags & IMA_DIGSIG_REQUIRED) ||
517b7e27bc1SMimi Zohar 		     (inode->i_size == 0)))
518b151d6b0SDmitry Kasatkin 			status = INTEGRITY_PASS;
5192fe5d6deSMimi Zohar 		goto out;
5202fe5d6deSMimi Zohar 	}
5212fe5d6deSMimi Zohar 
522d2ee2cfcSHuaxin Lu 	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
523d2ee2cfcSHuaxin Lu 				 rc < 0 ? 0 : rc, iint);
524f5e51fa3SThiago Jung Bauermann 	switch (status) {
525f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_PASS:
526f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_PASS_IMMUTABLE:
527f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_UNKNOWN:
528f5e51fa3SThiago Jung Bauermann 		break;
529f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_NOXATTRS:	/* No EVM protected xattrs. */
53039b07096SThiago Jung Bauermann 		/* It's fine not to have xattrs when using a modsig. */
53139b07096SThiago Jung Bauermann 		if (try_modsig)
53239b07096SThiago Jung Bauermann 			break;
533df561f66SGustavo A. R. Silva 		fallthrough;
534f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
5352fe5d6deSMimi Zohar 		cause = "missing-HMAC";
536f5e51fa3SThiago Jung Bauermann 		goto out;
537cdef685bSRoberto Sassu 	case INTEGRITY_FAIL_IMMUTABLE:
5387aa5783dSRoberto Sassu 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
53955748ac6SMimi Zohar 		cause = "invalid-fail-immutable";
54055748ac6SMimi Zohar 		goto out;
541f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_FAIL:		/* Invalid HMAC/signature. */
5422fe5d6deSMimi Zohar 		cause = "invalid-HMAC";
5432fe5d6deSMimi Zohar 		goto out;
544f5e51fa3SThiago Jung Bauermann 	default:
545f5e51fa3SThiago Jung Bauermann 		WARN_ONCE(true, "Unexpected integrity status %d\n", status);
5462fe5d6deSMimi Zohar 	}
547f5e51fa3SThiago Jung Bauermann 
548a5fbeb61SThiago Jung Bauermann 	if (xattr_value)
549a5fbeb61SThiago Jung Bauermann 		rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
550a5fbeb61SThiago Jung Bauermann 				  &cause);
5518606404fSDmitry Kasatkin 
55239b07096SThiago Jung Bauermann 	/*
55339b07096SThiago Jung Bauermann 	 * If we have a modsig and either no imasig or the imasig's key isn't
55439b07096SThiago Jung Bauermann 	 * known, then try verifying the modsig.
55539b07096SThiago Jung Bauermann 	 */
55639b07096SThiago Jung Bauermann 	if (try_modsig &&
55739b07096SThiago Jung Bauermann 	    (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
55839b07096SThiago Jung Bauermann 	     rc == -ENOKEY))
55939b07096SThiago Jung Bauermann 		rc = modsig_verify(func, modsig, &status, &cause);
56039b07096SThiago Jung Bauermann 
5612fe5d6deSMimi Zohar out:
56257b56ac6SMimi Zohar 	/*
56357b56ac6SMimi Zohar 	 * File signatures on some filesystems can not be properly verified.
5649e67028eSMimi Zohar 	 * When such filesystems are mounted by an untrusted mounter or on a
5659e67028eSMimi Zohar 	 * system not willing to accept such a risk, fail the file signature
5669e67028eSMimi Zohar 	 * verification.
56757b56ac6SMimi Zohar 	 */
5689e67028eSMimi Zohar 	if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
5699e67028eSMimi Zohar 	    ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
5709e67028eSMimi Zohar 	     (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
57157b56ac6SMimi Zohar 		status = INTEGRITY_FAIL;
57257b56ac6SMimi Zohar 		cause = "unverifiable-signature";
57357b56ac6SMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
57457b56ac6SMimi Zohar 				    op, cause, rc, 0);
57557b56ac6SMimi Zohar 	} else if (status != INTEGRITY_PASS) {
576f5e51fa3SThiago Jung Bauermann 		/* Fix mode, but don't replace file signatures. */
57739b07096SThiago Jung Bauermann 		if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
5788606404fSDmitry Kasatkin 		    (!xattr_value ||
5798606404fSDmitry Kasatkin 		     xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
580def3e8b9SDmitry Kasatkin 			if (!ima_fix_xattr(dentry, iint))
5812fe5d6deSMimi Zohar 				status = INTEGRITY_PASS;
582f5e51fa3SThiago Jung Bauermann 		}
583f5e51fa3SThiago Jung Bauermann 
5847aa5783dSRoberto Sassu 		/*
5857aa5783dSRoberto Sassu 		 * Permit new files with file/EVM portable signatures, but
5867aa5783dSRoberto Sassu 		 * without data.
5877aa5783dSRoberto Sassu 		 */
588f5e51fa3SThiago Jung Bauermann 		if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
5897aa5783dSRoberto Sassu 		    test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
59005d1a717SMimi Zohar 			status = INTEGRITY_PASS;
5912fe5d6deSMimi Zohar 		}
592f5e51fa3SThiago Jung Bauermann 
5932fe5d6deSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
5942fe5d6deSMimi Zohar 				    op, cause, rc, 0);
5958606404fSDmitry Kasatkin 	} else {
596d79d72e0SMimi Zohar 		ima_cache_flags(iint, func);
5972fe5d6deSMimi Zohar 	}
59857b56ac6SMimi Zohar 
599d79d72e0SMimi Zohar 	ima_set_cache_status(iint, func, status);
6002fe5d6deSMimi Zohar 	return status;
6012fe5d6deSMimi Zohar }
6022fe5d6deSMimi Zohar 
6032fe5d6deSMimi Zohar /*
6042fe5d6deSMimi Zohar  * ima_update_xattr - update 'security.ima' hash value
6052fe5d6deSMimi Zohar  */
ima_update_xattr(struct integrity_iint_cache * iint,struct file * file)6062fe5d6deSMimi Zohar void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
6072fe5d6deSMimi Zohar {
608e71b9dffSMiklos Szeredi 	struct dentry *dentry = file_dentry(file);
6092fe5d6deSMimi Zohar 	int rc = 0;
6102fe5d6deSMimi Zohar 
6118606404fSDmitry Kasatkin 	/* do not collect and update hash for digital signatures */
6120d73a552SDmitry Kasatkin 	if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
6138606404fSDmitry Kasatkin 		return;
6148606404fSDmitry Kasatkin 
615da1b0029SMimi Zohar 	if ((iint->ima_file_status != INTEGRITY_PASS) &&
616da1b0029SMimi Zohar 	    !(iint->flags & IMA_HASH))
617020aae3eSRoberto Sassu 		return;
618020aae3eSRoberto Sassu 
61915588227SThiago Jung Bauermann 	rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL);
6202fe5d6deSMimi Zohar 	if (rc < 0)
6212fe5d6deSMimi Zohar 		return;
6228606404fSDmitry Kasatkin 
6230d73a552SDmitry Kasatkin 	inode_lock(file_inode(file));
6242fe5d6deSMimi Zohar 	ima_fix_xattr(dentry, iint);
6250d73a552SDmitry Kasatkin 	inode_unlock(file_inode(file));
6262fe5d6deSMimi Zohar }
6272fe5d6deSMimi Zohar 
6282fe5d6deSMimi Zohar /**
6292fe5d6deSMimi Zohar  * ima_inode_post_setattr - reflect file metadata changes
63039f60c1cSChristian Brauner  * @idmap:  idmap of the mount the inode was found from
6312fe5d6deSMimi Zohar  * @dentry: pointer to the affected dentry
6322fe5d6deSMimi Zohar  *
6332fe5d6deSMimi Zohar  * Changes to a dentry's metadata might result in needing to appraise.
6342fe5d6deSMimi Zohar  *
6352fe5d6deSMimi Zohar  * This function is called from notify_change(), which expects the caller
6362fe5d6deSMimi Zohar  * to lock the inode's i_mutex.
6372fe5d6deSMimi Zohar  */
ima_inode_post_setattr(struct mnt_idmap * idmap,struct dentry * dentry)63839f60c1cSChristian Brauner void ima_inode_post_setattr(struct mnt_idmap *idmap,
639a2d2329eSChristian Brauner 			    struct dentry *dentry)
6402fe5d6deSMimi Zohar {
641c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
6422fe5d6deSMimi Zohar 	struct integrity_iint_cache *iint;
643da1b0029SMimi Zohar 	int action;
6442fe5d6deSMimi Zohar 
645a756024eSRoberto Sassu 	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
6465d6c3191SAndreas Gruenbacher 	    || !(inode->i_opflags & IOP_XATTR))
6472fe5d6deSMimi Zohar 		return;
6482fe5d6deSMimi Zohar 
64939f60c1cSChristian Brauner 	action = ima_must_appraise(idmap, inode, MAY_ACCESS, POST_SETATTR);
6500d73a552SDmitry Kasatkin 	iint = integrity_iint_find(inode);
6510d73a552SDmitry Kasatkin 	if (iint) {
6520d73a552SDmitry Kasatkin 		set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
653da1b0029SMimi Zohar 		if (!action)
6540d73a552SDmitry Kasatkin 			clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
6550d73a552SDmitry Kasatkin 	}
6562fe5d6deSMimi Zohar }
65742c63330SMimi Zohar 
65842c63330SMimi Zohar /*
65942c63330SMimi Zohar  * ima_protect_xattr - protect 'security.ima'
66042c63330SMimi Zohar  *
66142c63330SMimi Zohar  * Ensure that not just anyone can modify or remove 'security.ima'.
66242c63330SMimi Zohar  */
ima_protect_xattr(struct dentry * dentry,const char * xattr_name,const void * xattr_value,size_t xattr_value_len)66342c63330SMimi Zohar static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
66442c63330SMimi Zohar 			     const void *xattr_value, size_t xattr_value_len)
66542c63330SMimi Zohar {
66642c63330SMimi Zohar 	if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) {
66742c63330SMimi Zohar 		if (!capable(CAP_SYS_ADMIN))
66842c63330SMimi Zohar 			return -EPERM;
66942c63330SMimi Zohar 		return 1;
67042c63330SMimi Zohar 	}
67142c63330SMimi Zohar 	return 0;
67242c63330SMimi Zohar }
67342c63330SMimi Zohar 
ima_reset_appraise_flags(struct inode * inode,int digsig)674060bdebfSMimi Zohar static void ima_reset_appraise_flags(struct inode *inode, int digsig)
67542c63330SMimi Zohar {
67642c63330SMimi Zohar 	struct integrity_iint_cache *iint;
67742c63330SMimi Zohar 
678a756024eSRoberto Sassu 	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
67942c63330SMimi Zohar 		return;
68042c63330SMimi Zohar 
68142c63330SMimi Zohar 	iint = integrity_iint_find(inode);
68242c63330SMimi Zohar 	if (!iint)
68342c63330SMimi Zohar 		return;
684a422638dSEric Richter 	iint->measured_pcrs = 0;
6850d73a552SDmitry Kasatkin 	set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
686060bdebfSMimi Zohar 	if (digsig)
6870d73a552SDmitry Kasatkin 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
6880d73a552SDmitry Kasatkin 	else
6890d73a552SDmitry Kasatkin 		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
69042c63330SMimi Zohar }
69142c63330SMimi Zohar 
69250f742ddSTHOBY Simon /**
69350f742ddSTHOBY Simon  * validate_hash_algo() - Block setxattr with unsupported hash algorithms
69450f742ddSTHOBY Simon  * @dentry: object of the setxattr()
69550f742ddSTHOBY Simon  * @xattr_value: userland supplied xattr value
69650f742ddSTHOBY Simon  * @xattr_value_len: length of xattr_value
69750f742ddSTHOBY Simon  *
69850f742ddSTHOBY Simon  * The xattr value is mapped to its hash algorithm, and this algorithm
69950f742ddSTHOBY Simon  * must be built in the kernel for the setxattr to be allowed.
70050f742ddSTHOBY Simon  *
70150f742ddSTHOBY Simon  * Emit an audit message when the algorithm is invalid.
70250f742ddSTHOBY Simon  *
70350f742ddSTHOBY Simon  * Return: 0 on success, else an error.
70450f742ddSTHOBY Simon  */
validate_hash_algo(struct dentry * dentry,const struct evm_ima_xattr_data * xattr_value,size_t xattr_value_len)70550f742ddSTHOBY Simon static int validate_hash_algo(struct dentry *dentry,
70650f742ddSTHOBY Simon 			      const struct evm_ima_xattr_data *xattr_value,
70750f742ddSTHOBY Simon 			      size_t xattr_value_len)
70850f742ddSTHOBY Simon {
70950f742ddSTHOBY Simon 	char *path = NULL, *pathbuf = NULL;
71050f742ddSTHOBY Simon 	enum hash_algo xattr_hash_algo;
7114f2946aaSTHOBY Simon 	const char *errmsg = "unavailable-hash-algorithm";
7124f2946aaSTHOBY Simon 	unsigned int allowed_hashes;
71350f742ddSTHOBY Simon 
71450f742ddSTHOBY Simon 	xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
71550f742ddSTHOBY Simon 
7164f2946aaSTHOBY Simon 	allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
7174f2946aaSTHOBY Simon 
7184f2946aaSTHOBY Simon 	if (allowed_hashes) {
7194f2946aaSTHOBY Simon 		/* success if the algorithm is allowed in the ima policy */
7204f2946aaSTHOBY Simon 		if (allowed_hashes & (1U << xattr_hash_algo))
72150f742ddSTHOBY Simon 			return 0;
72250f742ddSTHOBY Simon 
7234f2946aaSTHOBY Simon 		/*
7244f2946aaSTHOBY Simon 		 * We use a different audit message when the hash algorithm
7254f2946aaSTHOBY Simon 		 * is denied by a policy rule, instead of not being built
7264f2946aaSTHOBY Simon 		 * in the kernel image
7274f2946aaSTHOBY Simon 		 */
7284f2946aaSTHOBY Simon 		errmsg = "denied-hash-algorithm";
7294f2946aaSTHOBY Simon 	} else {
7304f2946aaSTHOBY Simon 		if (likely(xattr_hash_algo == ima_hash_algo))
7314f2946aaSTHOBY Simon 			return 0;
7324f2946aaSTHOBY Simon 
7334f2946aaSTHOBY Simon 		/* allow any xattr using an algorithm built in the kernel */
7344f2946aaSTHOBY Simon 		if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0))
7354f2946aaSTHOBY Simon 			return 0;
7364f2946aaSTHOBY Simon 	}
7374f2946aaSTHOBY Simon 
73850f742ddSTHOBY Simon 	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
73950f742ddSTHOBY Simon 	if (!pathbuf)
74050f742ddSTHOBY Simon 		return -EACCES;
74150f742ddSTHOBY Simon 
74250f742ddSTHOBY Simon 	path = dentry_path(dentry, pathbuf, PATH_MAX);
74350f742ddSTHOBY Simon 
74450f742ddSTHOBY Simon 	integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
7454f2946aaSTHOBY Simon 			    "set_data", errmsg, -EACCES, 0);
74650f742ddSTHOBY Simon 
74750f742ddSTHOBY Simon 	kfree(pathbuf);
74850f742ddSTHOBY Simon 
74950f742ddSTHOBY Simon 	return -EACCES;
75050f742ddSTHOBY Simon }
75150f742ddSTHOBY Simon 
ima_inode_setxattr(struct dentry * dentry,const char * xattr_name,const void * xattr_value,size_t xattr_value_len)75242c63330SMimi Zohar int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
75342c63330SMimi Zohar 		       const void *xattr_value, size_t xattr_value_len)
75442c63330SMimi Zohar {
755060bdebfSMimi Zohar 	const struct evm_ima_xattr_data *xvalue = xattr_value;
756e3ccfe1aSRoberto Sassu 	int digsig = 0;
75742c63330SMimi Zohar 	int result;
7585926586fSMimi Zohar 	int err;
75942c63330SMimi Zohar 
76042c63330SMimi Zohar 	result = ima_protect_xattr(dentry, xattr_name, xattr_value,
76142c63330SMimi Zohar 				   xattr_value_len);
76242c63330SMimi Zohar 	if (result == 1) {
763a48fda9dSDmitry Kasatkin 		if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
764a48fda9dSDmitry Kasatkin 			return -EINVAL;
7655926586fSMimi Zohar 
7665926586fSMimi Zohar 		err = validate_hash_algo(dentry, xvalue, xattr_value_len);
7675926586fSMimi Zohar 		if (err)
7685926586fSMimi Zohar 			return err;
7695926586fSMimi Zohar 
770e3ccfe1aSRoberto Sassu 		digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
7717aa5783dSRoberto Sassu 	} else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
7727aa5783dSRoberto Sassu 		digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
773e3ccfe1aSRoberto Sassu 	}
774e3ccfe1aSRoberto Sassu 	if (result == 1 || evm_revalidate_status(xattr_name)) {
775e3ccfe1aSRoberto Sassu 		ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
7765926586fSMimi Zohar 		if (result == 1)
7775926586fSMimi Zohar 			result = 0;
77842c63330SMimi Zohar 	}
77942c63330SMimi Zohar 	return result;
78042c63330SMimi Zohar }
78142c63330SMimi Zohar 
ima_inode_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,const char * acl_name,struct posix_acl * kacl)782700b7940SChristian Brauner int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
783e61b135fSChristian Brauner 		      const char *acl_name, struct posix_acl *kacl)
784e61b135fSChristian Brauner {
785e61b135fSChristian Brauner 	if (evm_revalidate_status(acl_name))
786e61b135fSChristian Brauner 		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
787e61b135fSChristian Brauner 
788e61b135fSChristian Brauner 	return 0;
789e61b135fSChristian Brauner }
790e61b135fSChristian Brauner 
ima_inode_removexattr(struct dentry * dentry,const char * xattr_name)79142c63330SMimi Zohar int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
79242c63330SMimi Zohar {
79342c63330SMimi Zohar 	int result;
79442c63330SMimi Zohar 
79542c63330SMimi Zohar 	result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
796e3ccfe1aSRoberto Sassu 	if (result == 1 || evm_revalidate_status(xattr_name)) {
797c6f493d6SDavid Howells 		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
798e3ccfe1aSRoberto Sassu 		if (result == 1)
79942c63330SMimi Zohar 			result = 0;
80042c63330SMimi Zohar 	}
80142c63330SMimi Zohar 	return result;
80242c63330SMimi Zohar }
803