xref: /openbmc/linux/security/integrity/ima/ima_appraise.c (revision b886d83c5b621abc84ff9616f14c529be3f6b147)
1*b886d83cSThomas 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  */
8876979c9SPaul Gortmaker #include <linux/init.h>
92fe5d6deSMimi Zohar #include <linux/file.h>
102fe5d6deSMimi Zohar #include <linux/fs.h>
112fe5d6deSMimi Zohar #include <linux/xattr.h>
122fe5d6deSMimi Zohar #include <linux/magic.h>
132fe5d6deSMimi Zohar #include <linux/ima.h>
142fe5d6deSMimi Zohar #include <linux/evm.h>
152fe5d6deSMimi Zohar 
162fe5d6deSMimi Zohar #include "ima.h"
172fe5d6deSMimi Zohar 
182fe5d6deSMimi Zohar static int __init default_appraise_setup(char *str)
192fe5d6deSMimi Zohar {
20e1f5e01fSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
212fe5d6deSMimi Zohar 	if (strncmp(str, "off", 3) == 0)
222fe5d6deSMimi Zohar 		ima_appraise = 0;
232faa6ef3SDmitry Kasatkin 	else if (strncmp(str, "log", 3) == 0)
242faa6ef3SDmitry Kasatkin 		ima_appraise = IMA_APPRAISE_LOG;
252fe5d6deSMimi Zohar 	else if (strncmp(str, "fix", 3) == 0)
262fe5d6deSMimi Zohar 		ima_appraise = IMA_APPRAISE_FIX;
27e1f5e01fSMimi Zohar #endif
282fe5d6deSMimi Zohar 	return 1;
292fe5d6deSMimi Zohar }
302fe5d6deSMimi Zohar 
312fe5d6deSMimi Zohar __setup("ima_appraise=", default_appraise_setup);
322fe5d6deSMimi Zohar 
332fe5d6deSMimi Zohar /*
346f6723e2SMimi Zohar  * is_ima_appraise_enabled - return appraise status
356f6723e2SMimi Zohar  *
366f6723e2SMimi Zohar  * Only return enabled, if not in ima_appraise="fix" or "log" modes.
376f6723e2SMimi Zohar  */
386f6723e2SMimi Zohar bool is_ima_appraise_enabled(void)
396f6723e2SMimi Zohar {
40e5729f86SThiago Jung Bauermann 	return ima_appraise & IMA_APPRAISE_ENFORCE;
416f6723e2SMimi Zohar }
426f6723e2SMimi Zohar 
436f6723e2SMimi Zohar /*
442fe5d6deSMimi Zohar  * ima_must_appraise - set appraise flag
452fe5d6deSMimi Zohar  *
46da1b0029SMimi Zohar  * Return 1 to appraise or hash
472fe5d6deSMimi Zohar  */
48d26e1936SDmitry Kasatkin int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
492fe5d6deSMimi Zohar {
50d906c10dSMatthew Garrett 	u32 secid;
51d906c10dSMatthew Garrett 
5207f6a794SMimi Zohar 	if (!ima_appraise)
532fe5d6deSMimi Zohar 		return 0;
5407f6a794SMimi Zohar 
55d906c10dSMatthew Garrett 	security_task_getsecid(current, &secid);
56d906c10dSMatthew Garrett 	return ima_match_policy(inode, current_cred(), secid, func, mask,
57d906c10dSMatthew Garrett 				IMA_APPRAISE | IMA_HASH, NULL);
582fe5d6deSMimi Zohar }
592fe5d6deSMimi Zohar 
60def3e8b9SDmitry Kasatkin static int ima_fix_xattr(struct dentry *dentry,
612fe5d6deSMimi Zohar 			 struct integrity_iint_cache *iint)
622fe5d6deSMimi Zohar {
633ea7a560SDmitry Kasatkin 	int rc, offset;
643ea7a560SDmitry Kasatkin 	u8 algo = iint->ima_hash->algo;
653ea7a560SDmitry Kasatkin 
663ea7a560SDmitry Kasatkin 	if (algo <= HASH_ALGO_SHA1) {
673ea7a560SDmitry Kasatkin 		offset = 1;
683ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
693ea7a560SDmitry Kasatkin 	} else {
703ea7a560SDmitry Kasatkin 		offset = 0;
713ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
723ea7a560SDmitry Kasatkin 		iint->ima_hash->xattr.ng.algo = algo;
733ea7a560SDmitry Kasatkin 	}
743ea7a560SDmitry Kasatkin 	rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
753ea7a560SDmitry Kasatkin 				   &iint->ima_hash->xattr.data[offset],
763ea7a560SDmitry Kasatkin 				   (sizeof(iint->ima_hash->xattr) - offset) +
773ea7a560SDmitry Kasatkin 				   iint->ima_hash->length, 0);
783ea7a560SDmitry Kasatkin 	return rc;
792fe5d6deSMimi Zohar }
802fe5d6deSMimi Zohar 
81d79d72e0SMimi Zohar /* Return specific func appraised cached result */
82d79d72e0SMimi Zohar enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
834ad87a3dSMimi Zohar 					   enum ima_hooks func)
84d79d72e0SMimi Zohar {
85d79d72e0SMimi Zohar 	switch (func) {
86d79d72e0SMimi Zohar 	case MMAP_CHECK:
87d79d72e0SMimi Zohar 		return iint->ima_mmap_status;
88d79d72e0SMimi Zohar 	case BPRM_CHECK:
89d79d72e0SMimi Zohar 		return iint->ima_bprm_status;
90d906c10dSMatthew Garrett 	case CREDS_CHECK:
91d906c10dSMatthew Garrett 		return iint->ima_creds_status;
92d79d72e0SMimi Zohar 	case FILE_CHECK:
93c6af8efeSMimi Zohar 	case POST_SETATTR:
94d79d72e0SMimi Zohar 		return iint->ima_file_status;
95c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
96c6af8efeSMimi Zohar 	default:
97c6af8efeSMimi Zohar 		return iint->ima_read_status;
98d79d72e0SMimi Zohar 	}
99d79d72e0SMimi Zohar }
100d79d72e0SMimi Zohar 
101d79d72e0SMimi Zohar static void ima_set_cache_status(struct integrity_iint_cache *iint,
1024ad87a3dSMimi Zohar 				 enum ima_hooks func,
1034ad87a3dSMimi Zohar 				 enum integrity_status status)
104d79d72e0SMimi Zohar {
105d79d72e0SMimi Zohar 	switch (func) {
106d79d72e0SMimi Zohar 	case MMAP_CHECK:
107d79d72e0SMimi Zohar 		iint->ima_mmap_status = status;
108d79d72e0SMimi Zohar 		break;
109d79d72e0SMimi Zohar 	case BPRM_CHECK:
110d79d72e0SMimi Zohar 		iint->ima_bprm_status = status;
111d79d72e0SMimi Zohar 		break;
112d906c10dSMatthew Garrett 	case CREDS_CHECK:
113d906c10dSMatthew Garrett 		iint->ima_creds_status = status;
11409186e50SGustavo A. R. Silva 		break;
115d79d72e0SMimi Zohar 	case FILE_CHECK:
116c6af8efeSMimi Zohar 	case POST_SETATTR:
117d79d72e0SMimi Zohar 		iint->ima_file_status = status;
118c6af8efeSMimi Zohar 		break;
119c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
120c6af8efeSMimi Zohar 	default:
121c6af8efeSMimi Zohar 		iint->ima_read_status = status;
122c6af8efeSMimi Zohar 		break;
123d79d72e0SMimi Zohar 	}
124d79d72e0SMimi Zohar }
125d79d72e0SMimi Zohar 
1264ad87a3dSMimi Zohar static void ima_cache_flags(struct integrity_iint_cache *iint,
1274ad87a3dSMimi Zohar 			     enum ima_hooks func)
128d79d72e0SMimi Zohar {
129d79d72e0SMimi Zohar 	switch (func) {
130d79d72e0SMimi Zohar 	case MMAP_CHECK:
131d79d72e0SMimi Zohar 		iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
132d79d72e0SMimi Zohar 		break;
133d79d72e0SMimi Zohar 	case BPRM_CHECK:
134d79d72e0SMimi Zohar 		iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
135d79d72e0SMimi Zohar 		break;
136d906c10dSMatthew Garrett 	case CREDS_CHECK:
137d906c10dSMatthew Garrett 		iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
138d906c10dSMatthew Garrett 		break;
139d79d72e0SMimi Zohar 	case FILE_CHECK:
140c6af8efeSMimi Zohar 	case POST_SETATTR:
141d79d72e0SMimi Zohar 		iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
142c6af8efeSMimi Zohar 		break;
143c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
144c6af8efeSMimi Zohar 	default:
145c6af8efeSMimi Zohar 		iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
146c6af8efeSMimi Zohar 		break;
147d79d72e0SMimi Zohar 	}
148d79d72e0SMimi Zohar }
149d79d72e0SMimi Zohar 
1501525b06dSDmitry Kasatkin enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
1511525b06dSDmitry Kasatkin 				 int xattr_len)
152d3634d0fSDmitry Kasatkin {
153d3634d0fSDmitry Kasatkin 	struct signature_v2_hdr *sig;
154b4bfec7fSSeth Forshee 	enum hash_algo ret;
155d3634d0fSDmitry Kasatkin 
1563ea7a560SDmitry Kasatkin 	if (!xattr_value || xattr_len < 2)
1571525b06dSDmitry Kasatkin 		/* return default hash algo */
1581525b06dSDmitry Kasatkin 		return ima_hash_algo;
159d3634d0fSDmitry Kasatkin 
1603ea7a560SDmitry Kasatkin 	switch (xattr_value->type) {
1613ea7a560SDmitry Kasatkin 	case EVM_IMA_XATTR_DIGSIG:
1623ea7a560SDmitry Kasatkin 		sig = (typeof(sig))xattr_value;
1633ea7a560SDmitry Kasatkin 		if (sig->version != 2 || xattr_len <= sizeof(*sig))
1641525b06dSDmitry Kasatkin 			return ima_hash_algo;
1651525b06dSDmitry Kasatkin 		return sig->hash_algo;
1663ea7a560SDmitry Kasatkin 		break;
1673ea7a560SDmitry Kasatkin 	case IMA_XATTR_DIGEST_NG:
168b4bfec7fSSeth Forshee 		ret = xattr_value->digest[0];
169b4bfec7fSSeth Forshee 		if (ret < HASH_ALGO__LAST)
170b4bfec7fSSeth Forshee 			return ret;
1713ea7a560SDmitry Kasatkin 		break;
1723ea7a560SDmitry Kasatkin 	case IMA_XATTR_DIGEST:
1733ea7a560SDmitry Kasatkin 		/* this is for backward compatibility */
1743ea7a560SDmitry Kasatkin 		if (xattr_len == 21) {
1753ea7a560SDmitry Kasatkin 			unsigned int zero = 0;
1763ea7a560SDmitry Kasatkin 			if (!memcmp(&xattr_value->digest[16], &zero, 4))
1771525b06dSDmitry Kasatkin 				return HASH_ALGO_MD5;
1783ea7a560SDmitry Kasatkin 			else
1791525b06dSDmitry Kasatkin 				return HASH_ALGO_SHA1;
1803ea7a560SDmitry Kasatkin 		} else if (xattr_len == 17)
1811525b06dSDmitry Kasatkin 			return HASH_ALGO_MD5;
1823ea7a560SDmitry Kasatkin 		break;
1833ea7a560SDmitry Kasatkin 	}
1841525b06dSDmitry Kasatkin 
1851525b06dSDmitry Kasatkin 	/* return default hash algo */
1861525b06dSDmitry Kasatkin 	return ima_hash_algo;
187d3634d0fSDmitry Kasatkin }
188d3634d0fSDmitry Kasatkin 
189d3634d0fSDmitry Kasatkin int ima_read_xattr(struct dentry *dentry,
190d3634d0fSDmitry Kasatkin 		   struct evm_ima_xattr_data **xattr_value)
191d3634d0fSDmitry Kasatkin {
1925d6c3191SAndreas Gruenbacher 	ssize_t ret;
193d3634d0fSDmitry Kasatkin 
1945d6c3191SAndreas Gruenbacher 	ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
195d3634d0fSDmitry Kasatkin 				 0, GFP_NOFS);
1965d6c3191SAndreas Gruenbacher 	if (ret == -EOPNOTSUPP)
1975d6c3191SAndreas Gruenbacher 		ret = 0;
1985d6c3191SAndreas Gruenbacher 	return ret;
199d3634d0fSDmitry Kasatkin }
200d3634d0fSDmitry Kasatkin 
2012fe5d6deSMimi Zohar /*
2022fe5d6deSMimi Zohar  * ima_appraise_measurement - appraise file measurement
2032fe5d6deSMimi Zohar  *
2042fe5d6deSMimi Zohar  * Call evm_verifyxattr() to verify the integrity of 'security.ima'.
2052fe5d6deSMimi Zohar  * Assuming success, compare the xattr hash with the collected measurement.
2062fe5d6deSMimi Zohar  *
2072fe5d6deSMimi Zohar  * Return 0 on success, error code otherwise
2082fe5d6deSMimi Zohar  */
2094ad87a3dSMimi Zohar int ima_appraise_measurement(enum ima_hooks func,
2104ad87a3dSMimi Zohar 			     struct integrity_iint_cache *iint,
211d3634d0fSDmitry Kasatkin 			     struct file *file, const unsigned char *filename,
212d3634d0fSDmitry Kasatkin 			     struct evm_ima_xattr_data *xattr_value,
2136035a27bSAl Viro 			     int xattr_len)
2142fe5d6deSMimi Zohar {
21552a13284SMimi Zohar 	static const char op[] = "appraise_data";
216f5e51fa3SThiago Jung Bauermann 	const char *cause = "unknown";
217e71b9dffSMiklos Szeredi 	struct dentry *dentry = file_dentry(file);
218c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
2192fe5d6deSMimi Zohar 	enum integrity_status status = INTEGRITY_UNKNOWN;
2203ea7a560SDmitry Kasatkin 	int rc = xattr_len, hash_start = 0;
2212fe5d6deSMimi Zohar 
2225d6c3191SAndreas Gruenbacher 	if (!(inode->i_opflags & IOP_XATTR))
2232fe5d6deSMimi Zohar 		return INTEGRITY_UNKNOWN;
2242fe5d6deSMimi Zohar 
2252fe5d6deSMimi Zohar 	if (rc <= 0) {
2262fe5d6deSMimi Zohar 		if (rc && rc != -ENODATA)
2272fe5d6deSMimi Zohar 			goto out;
2282fe5d6deSMimi Zohar 
229915d9d25SThiago Jung Bauermann 		cause = iint->flags & IMA_DIGSIG_REQUIRED ?
230915d9d25SThiago Jung Bauermann 				"IMA-signature-required" : "missing-hash";
231b151d6b0SDmitry Kasatkin 		status = INTEGRITY_NOLABEL;
2326035a27bSAl Viro 		if (file->f_mode & FMODE_CREATED)
233b151d6b0SDmitry Kasatkin 			iint->flags |= IMA_NEW_FILE;
2341ac202e9SDaniel Glöckner 		if ((iint->flags & IMA_NEW_FILE) &&
235b7e27bc1SMimi Zohar 		    (!(iint->flags & IMA_DIGSIG_REQUIRED) ||
236b7e27bc1SMimi Zohar 		     (inode->i_size == 0)))
237b151d6b0SDmitry Kasatkin 			status = INTEGRITY_PASS;
2382fe5d6deSMimi Zohar 		goto out;
2392fe5d6deSMimi Zohar 	}
2402fe5d6deSMimi Zohar 
2418606404fSDmitry Kasatkin 	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
242f5e51fa3SThiago Jung Bauermann 	switch (status) {
243f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_PASS:
244f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_PASS_IMMUTABLE:
245f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_UNKNOWN:
246f5e51fa3SThiago Jung Bauermann 		break;
247f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_NOXATTRS:	/* No EVM protected xattrs. */
248f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
2492fe5d6deSMimi Zohar 		cause = "missing-HMAC";
250f5e51fa3SThiago Jung Bauermann 		goto out;
251f5e51fa3SThiago Jung Bauermann 	case INTEGRITY_FAIL:		/* Invalid HMAC/signature. */
2522fe5d6deSMimi Zohar 		cause = "invalid-HMAC";
2532fe5d6deSMimi Zohar 		goto out;
254f5e51fa3SThiago Jung Bauermann 	default:
255f5e51fa3SThiago Jung Bauermann 		WARN_ONCE(true, "Unexpected integrity status %d\n", status);
2562fe5d6deSMimi Zohar 	}
257f5e51fa3SThiago Jung Bauermann 
2588606404fSDmitry Kasatkin 	switch (xattr_value->type) {
2593ea7a560SDmitry Kasatkin 	case IMA_XATTR_DIGEST_NG:
2603ea7a560SDmitry Kasatkin 		/* first byte contains algorithm id */
2613ea7a560SDmitry Kasatkin 		hash_start = 1;
262bb543e39SThiago Jung Bauermann 		/* fall through */
2638606404fSDmitry Kasatkin 	case IMA_XATTR_DIGEST:
2640e5a247cSDmitry Kasatkin 		if (iint->flags & IMA_DIGSIG_REQUIRED) {
2657e9001f6SRichard Guy Briggs 			cause = "IMA-signature-required";
2660e5a247cSDmitry Kasatkin 			status = INTEGRITY_FAIL;
2670e5a247cSDmitry Kasatkin 			break;
2680e5a247cSDmitry Kasatkin 		}
2690d73a552SDmitry Kasatkin 		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
2703ea7a560SDmitry Kasatkin 		if (xattr_len - sizeof(xattr_value->type) - hash_start >=
2713ea7a560SDmitry Kasatkin 				iint->ima_hash->length)
272d3634d0fSDmitry Kasatkin 			/* xattr length may be longer. md5 hash in previous
273d3634d0fSDmitry Kasatkin 			   version occupied 20 bytes in xattr, instead of 16
274d3634d0fSDmitry Kasatkin 			 */
2753ea7a560SDmitry Kasatkin 			rc = memcmp(&xattr_value->digest[hash_start],
276a35c3fb6SDmitry Kasatkin 				    iint->ima_hash->digest,
277a35c3fb6SDmitry Kasatkin 				    iint->ima_hash->length);
278c7c8bb23SDmitry Kasatkin 		else
279c7c8bb23SDmitry Kasatkin 			rc = -EINVAL;
2802fe5d6deSMimi Zohar 		if (rc) {
2812fe5d6deSMimi Zohar 			cause = "invalid-hash";
2828606404fSDmitry Kasatkin 			status = INTEGRITY_FAIL;
2838606404fSDmitry Kasatkin 			break;
2842fe5d6deSMimi Zohar 		}
2852fe5d6deSMimi Zohar 		status = INTEGRITY_PASS;
2868606404fSDmitry Kasatkin 		break;
2878606404fSDmitry Kasatkin 	case EVM_IMA_XATTR_DIGSIG:
2880d73a552SDmitry Kasatkin 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
2898606404fSDmitry Kasatkin 		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
290d7cecb67SNayna Jain 					     (const char *)xattr_value,
291d7cecb67SNayna Jain 					     xattr_len,
292a35c3fb6SDmitry Kasatkin 					     iint->ima_hash->digest,
293a35c3fb6SDmitry Kasatkin 					     iint->ima_hash->length);
2948606404fSDmitry Kasatkin 		if (rc == -EOPNOTSUPP) {
2958606404fSDmitry Kasatkin 			status = INTEGRITY_UNKNOWN;
296d7cecb67SNayna Jain 			break;
297d7cecb67SNayna Jain 		}
298d7cecb67SNayna Jain 		if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
299d7cecb67SNayna Jain 		    func == KEXEC_KERNEL_CHECK)
300d7cecb67SNayna Jain 			rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
301d7cecb67SNayna Jain 						     (const char *)xattr_value,
302d7cecb67SNayna Jain 						     xattr_len,
303d7cecb67SNayna Jain 						     iint->ima_hash->digest,
304d7cecb67SNayna Jain 						     iint->ima_hash->length);
305d7cecb67SNayna Jain 		if (rc) {
3068606404fSDmitry Kasatkin 			cause = "invalid-signature";
3078606404fSDmitry Kasatkin 			status = INTEGRITY_FAIL;
3088606404fSDmitry Kasatkin 		} else {
3098606404fSDmitry Kasatkin 			status = INTEGRITY_PASS;
3108606404fSDmitry Kasatkin 		}
3118606404fSDmitry Kasatkin 		break;
3128606404fSDmitry Kasatkin 	default:
3138606404fSDmitry Kasatkin 		status = INTEGRITY_UNKNOWN;
3148606404fSDmitry Kasatkin 		cause = "unknown-ima-data";
3158606404fSDmitry Kasatkin 		break;
3168606404fSDmitry Kasatkin 	}
3178606404fSDmitry Kasatkin 
3182fe5d6deSMimi Zohar out:
31957b56ac6SMimi Zohar 	/*
32057b56ac6SMimi Zohar 	 * File signatures on some filesystems can not be properly verified.
3219e67028eSMimi Zohar 	 * When such filesystems are mounted by an untrusted mounter or on a
3229e67028eSMimi Zohar 	 * system not willing to accept such a risk, fail the file signature
3239e67028eSMimi Zohar 	 * verification.
32457b56ac6SMimi Zohar 	 */
3259e67028eSMimi Zohar 	if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
3269e67028eSMimi Zohar 	    ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
3279e67028eSMimi Zohar 	     (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
32857b56ac6SMimi Zohar 		status = INTEGRITY_FAIL;
32957b56ac6SMimi Zohar 		cause = "unverifiable-signature";
33057b56ac6SMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
33157b56ac6SMimi Zohar 				    op, cause, rc, 0);
33257b56ac6SMimi Zohar 	} else if (status != INTEGRITY_PASS) {
333f5e51fa3SThiago Jung Bauermann 		/* Fix mode, but don't replace file signatures. */
3348606404fSDmitry Kasatkin 		if ((ima_appraise & IMA_APPRAISE_FIX) &&
3358606404fSDmitry Kasatkin 		    (!xattr_value ||
3368606404fSDmitry Kasatkin 		     xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
337def3e8b9SDmitry Kasatkin 			if (!ima_fix_xattr(dentry, iint))
3382fe5d6deSMimi Zohar 				status = INTEGRITY_PASS;
339f5e51fa3SThiago Jung Bauermann 		}
340f5e51fa3SThiago Jung Bauermann 
341f5e51fa3SThiago Jung Bauermann 		/* Permit new files with file signatures, but without data. */
342f5e51fa3SThiago Jung Bauermann 		if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
343f5e51fa3SThiago Jung Bauermann 		    xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
34405d1a717SMimi Zohar 			status = INTEGRITY_PASS;
3452fe5d6deSMimi Zohar 		}
346f5e51fa3SThiago Jung Bauermann 
3472fe5d6deSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
3482fe5d6deSMimi Zohar 				    op, cause, rc, 0);
3498606404fSDmitry Kasatkin 	} else {
350d79d72e0SMimi Zohar 		ima_cache_flags(iint, func);
3512fe5d6deSMimi Zohar 	}
35257b56ac6SMimi Zohar 
353d79d72e0SMimi Zohar 	ima_set_cache_status(iint, func, status);
3542fe5d6deSMimi Zohar 	return status;
3552fe5d6deSMimi Zohar }
3562fe5d6deSMimi Zohar 
3572fe5d6deSMimi Zohar /*
3582fe5d6deSMimi Zohar  * ima_update_xattr - update 'security.ima' hash value
3592fe5d6deSMimi Zohar  */
3602fe5d6deSMimi Zohar void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
3612fe5d6deSMimi Zohar {
362e71b9dffSMiklos Szeredi 	struct dentry *dentry = file_dentry(file);
3632fe5d6deSMimi Zohar 	int rc = 0;
3642fe5d6deSMimi Zohar 
3658606404fSDmitry Kasatkin 	/* do not collect and update hash for digital signatures */
3660d73a552SDmitry Kasatkin 	if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
3678606404fSDmitry Kasatkin 		return;
3688606404fSDmitry Kasatkin 
369da1b0029SMimi Zohar 	if ((iint->ima_file_status != INTEGRITY_PASS) &&
370da1b0029SMimi Zohar 	    !(iint->flags & IMA_HASH))
371020aae3eSRoberto Sassu 		return;
372020aae3eSRoberto Sassu 
373cf222217SMimi Zohar 	rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
3742fe5d6deSMimi Zohar 	if (rc < 0)
3752fe5d6deSMimi Zohar 		return;
3768606404fSDmitry Kasatkin 
3770d73a552SDmitry Kasatkin 	inode_lock(file_inode(file));
3782fe5d6deSMimi Zohar 	ima_fix_xattr(dentry, iint);
3790d73a552SDmitry Kasatkin 	inode_unlock(file_inode(file));
3802fe5d6deSMimi Zohar }
3812fe5d6deSMimi Zohar 
3822fe5d6deSMimi Zohar /**
3832fe5d6deSMimi Zohar  * ima_inode_post_setattr - reflect file metadata changes
3842fe5d6deSMimi Zohar  * @dentry: pointer to the affected dentry
3852fe5d6deSMimi Zohar  *
3862fe5d6deSMimi Zohar  * Changes to a dentry's metadata might result in needing to appraise.
3872fe5d6deSMimi Zohar  *
3882fe5d6deSMimi Zohar  * This function is called from notify_change(), which expects the caller
3892fe5d6deSMimi Zohar  * to lock the inode's i_mutex.
3902fe5d6deSMimi Zohar  */
3912fe5d6deSMimi Zohar void ima_inode_post_setattr(struct dentry *dentry)
3922fe5d6deSMimi Zohar {
393c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
3942fe5d6deSMimi Zohar 	struct integrity_iint_cache *iint;
395da1b0029SMimi Zohar 	int action;
3962fe5d6deSMimi Zohar 
397a756024eSRoberto Sassu 	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
3985d6c3191SAndreas Gruenbacher 	    || !(inode->i_opflags & IOP_XATTR))
3992fe5d6deSMimi Zohar 		return;
4002fe5d6deSMimi Zohar 
401da1b0029SMimi Zohar 	action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
402da1b0029SMimi Zohar 	if (!action)
4035d6c3191SAndreas Gruenbacher 		__vfs_removexattr(dentry, XATTR_NAME_IMA);
4040d73a552SDmitry Kasatkin 	iint = integrity_iint_find(inode);
4050d73a552SDmitry Kasatkin 	if (iint) {
4060d73a552SDmitry Kasatkin 		set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
407da1b0029SMimi Zohar 		if (!action)
4080d73a552SDmitry Kasatkin 			clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
4090d73a552SDmitry Kasatkin 	}
4102fe5d6deSMimi Zohar }
41142c63330SMimi Zohar 
41242c63330SMimi Zohar /*
41342c63330SMimi Zohar  * ima_protect_xattr - protect 'security.ima'
41442c63330SMimi Zohar  *
41542c63330SMimi Zohar  * Ensure that not just anyone can modify or remove 'security.ima'.
41642c63330SMimi Zohar  */
41742c63330SMimi Zohar static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
41842c63330SMimi Zohar 			     const void *xattr_value, size_t xattr_value_len)
41942c63330SMimi Zohar {
42042c63330SMimi Zohar 	if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) {
42142c63330SMimi Zohar 		if (!capable(CAP_SYS_ADMIN))
42242c63330SMimi Zohar 			return -EPERM;
42342c63330SMimi Zohar 		return 1;
42442c63330SMimi Zohar 	}
42542c63330SMimi Zohar 	return 0;
42642c63330SMimi Zohar }
42742c63330SMimi Zohar 
428060bdebfSMimi Zohar static void ima_reset_appraise_flags(struct inode *inode, int digsig)
42942c63330SMimi Zohar {
43042c63330SMimi Zohar 	struct integrity_iint_cache *iint;
43142c63330SMimi Zohar 
432a756024eSRoberto Sassu 	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
43342c63330SMimi Zohar 		return;
43442c63330SMimi Zohar 
43542c63330SMimi Zohar 	iint = integrity_iint_find(inode);
43642c63330SMimi Zohar 	if (!iint)
43742c63330SMimi Zohar 		return;
438a422638dSEric Richter 	iint->measured_pcrs = 0;
4390d73a552SDmitry Kasatkin 	set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
440060bdebfSMimi Zohar 	if (digsig)
4410d73a552SDmitry Kasatkin 		set_bit(IMA_DIGSIG, &iint->atomic_flags);
4420d73a552SDmitry Kasatkin 	else
4430d73a552SDmitry Kasatkin 		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
44442c63330SMimi Zohar }
44542c63330SMimi Zohar 
44642c63330SMimi Zohar int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
44742c63330SMimi Zohar 		       const void *xattr_value, size_t xattr_value_len)
44842c63330SMimi Zohar {
449060bdebfSMimi Zohar 	const struct evm_ima_xattr_data *xvalue = xattr_value;
45042c63330SMimi Zohar 	int result;
45142c63330SMimi Zohar 
45242c63330SMimi Zohar 	result = ima_protect_xattr(dentry, xattr_name, xattr_value,
45342c63330SMimi Zohar 				   xattr_value_len);
45442c63330SMimi Zohar 	if (result == 1) {
455a48fda9dSDmitry Kasatkin 		if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
456a48fda9dSDmitry Kasatkin 			return -EINVAL;
457f5acb3dcSMimi Zohar 		ima_reset_appraise_flags(d_backing_inode(dentry),
458e5729f86SThiago Jung Bauermann 			xvalue->type == EVM_IMA_XATTR_DIGSIG);
45942c63330SMimi Zohar 		result = 0;
46042c63330SMimi Zohar 	}
46142c63330SMimi Zohar 	return result;
46242c63330SMimi Zohar }
46342c63330SMimi Zohar 
46442c63330SMimi Zohar int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
46542c63330SMimi Zohar {
46642c63330SMimi Zohar 	int result;
46742c63330SMimi Zohar 
46842c63330SMimi Zohar 	result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
46942c63330SMimi Zohar 	if (result == 1) {
470c6f493d6SDavid Howells 		ima_reset_appraise_flags(d_backing_inode(dentry), 0);
47142c63330SMimi Zohar 		result = 0;
47242c63330SMimi Zohar 	}
47342c63330SMimi Zohar 	return result;
47442c63330SMimi Zohar }
475