xref: /openbmc/linux/security/integrity/ima/ima_appraise.c (revision 2fe5d6def1672ae6635dd71867bf36dcfaa7434b)
1*2fe5d6deSMimi Zohar /*
2*2fe5d6deSMimi Zohar  * Copyright (C) 2011 IBM Corporation
3*2fe5d6deSMimi Zohar  *
4*2fe5d6deSMimi Zohar  * Author:
5*2fe5d6deSMimi Zohar  * Mimi Zohar <zohar@us.ibm.com>
6*2fe5d6deSMimi Zohar  *
7*2fe5d6deSMimi Zohar  * This program is free software; you can redistribute it and/or modify
8*2fe5d6deSMimi Zohar  * it under the terms of the GNU General Public License as published by
9*2fe5d6deSMimi Zohar  * the Free Software Foundation, version 2 of the License.
10*2fe5d6deSMimi Zohar  */
11*2fe5d6deSMimi Zohar #include <linux/module.h>
12*2fe5d6deSMimi Zohar #include <linux/file.h>
13*2fe5d6deSMimi Zohar #include <linux/fs.h>
14*2fe5d6deSMimi Zohar #include <linux/xattr.h>
15*2fe5d6deSMimi Zohar #include <linux/magic.h>
16*2fe5d6deSMimi Zohar #include <linux/ima.h>
17*2fe5d6deSMimi Zohar #include <linux/evm.h>
18*2fe5d6deSMimi Zohar 
19*2fe5d6deSMimi Zohar #include "ima.h"
20*2fe5d6deSMimi Zohar 
21*2fe5d6deSMimi Zohar static int __init default_appraise_setup(char *str)
22*2fe5d6deSMimi Zohar {
23*2fe5d6deSMimi Zohar 	if (strncmp(str, "off", 3) == 0)
24*2fe5d6deSMimi Zohar 		ima_appraise = 0;
25*2fe5d6deSMimi Zohar 	else if (strncmp(str, "fix", 3) == 0)
26*2fe5d6deSMimi Zohar 		ima_appraise = IMA_APPRAISE_FIX;
27*2fe5d6deSMimi Zohar 	return 1;
28*2fe5d6deSMimi Zohar }
29*2fe5d6deSMimi Zohar 
30*2fe5d6deSMimi Zohar __setup("ima_appraise=", default_appraise_setup);
31*2fe5d6deSMimi Zohar 
32*2fe5d6deSMimi Zohar /*
33*2fe5d6deSMimi Zohar  * ima_must_appraise - set appraise flag
34*2fe5d6deSMimi Zohar  *
35*2fe5d6deSMimi Zohar  * Return 1 to appraise
36*2fe5d6deSMimi Zohar  */
37*2fe5d6deSMimi Zohar int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask)
38*2fe5d6deSMimi Zohar {
39*2fe5d6deSMimi Zohar 	return 0;
40*2fe5d6deSMimi Zohar }
41*2fe5d6deSMimi Zohar 
42*2fe5d6deSMimi Zohar static void ima_fix_xattr(struct dentry *dentry,
43*2fe5d6deSMimi Zohar 			  struct integrity_iint_cache *iint)
44*2fe5d6deSMimi Zohar {
45*2fe5d6deSMimi Zohar 	iint->digest[0] = IMA_XATTR_DIGEST;
46*2fe5d6deSMimi Zohar 	__vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
47*2fe5d6deSMimi Zohar 			      iint->digest, IMA_DIGEST_SIZE + 1, 0);
48*2fe5d6deSMimi Zohar }
49*2fe5d6deSMimi Zohar 
50*2fe5d6deSMimi Zohar /*
51*2fe5d6deSMimi Zohar  * ima_appraise_measurement - appraise file measurement
52*2fe5d6deSMimi Zohar  *
53*2fe5d6deSMimi Zohar  * Call evm_verifyxattr() to verify the integrity of 'security.ima'.
54*2fe5d6deSMimi Zohar  * Assuming success, compare the xattr hash with the collected measurement.
55*2fe5d6deSMimi Zohar  *
56*2fe5d6deSMimi Zohar  * Return 0 on success, error code otherwise
57*2fe5d6deSMimi Zohar  */
58*2fe5d6deSMimi Zohar int ima_appraise_measurement(struct integrity_iint_cache *iint,
59*2fe5d6deSMimi Zohar 			     struct file *file, const unsigned char *filename)
60*2fe5d6deSMimi Zohar {
61*2fe5d6deSMimi Zohar 	struct dentry *dentry = file->f_dentry;
62*2fe5d6deSMimi Zohar 	struct inode *inode = dentry->d_inode;
63*2fe5d6deSMimi Zohar 	u8 xattr_value[IMA_DIGEST_SIZE];
64*2fe5d6deSMimi Zohar 	enum integrity_status status = INTEGRITY_UNKNOWN;
65*2fe5d6deSMimi Zohar 	const char *op = "appraise_data";
66*2fe5d6deSMimi Zohar 	char *cause = "unknown";
67*2fe5d6deSMimi Zohar 	int rc;
68*2fe5d6deSMimi Zohar 
69*2fe5d6deSMimi Zohar 	if (!ima_appraise)
70*2fe5d6deSMimi Zohar 		return 0;
71*2fe5d6deSMimi Zohar 	if (!inode->i_op->getxattr)
72*2fe5d6deSMimi Zohar 		return INTEGRITY_UNKNOWN;
73*2fe5d6deSMimi Zohar 
74*2fe5d6deSMimi Zohar 	if (iint->flags & IMA_APPRAISED)
75*2fe5d6deSMimi Zohar 		return iint->ima_status;
76*2fe5d6deSMimi Zohar 
77*2fe5d6deSMimi Zohar 	rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value,
78*2fe5d6deSMimi Zohar 				   IMA_DIGEST_SIZE);
79*2fe5d6deSMimi Zohar 	if (rc <= 0) {
80*2fe5d6deSMimi Zohar 		if (rc && rc != -ENODATA)
81*2fe5d6deSMimi Zohar 			goto out;
82*2fe5d6deSMimi Zohar 
83*2fe5d6deSMimi Zohar 		cause = "missing-hash";
84*2fe5d6deSMimi Zohar 		status =
85*2fe5d6deSMimi Zohar 		    (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
86*2fe5d6deSMimi Zohar 		goto out;
87*2fe5d6deSMimi Zohar 	}
88*2fe5d6deSMimi Zohar 
89*2fe5d6deSMimi Zohar 	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
90*2fe5d6deSMimi Zohar 	if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) {
91*2fe5d6deSMimi Zohar 		if ((status == INTEGRITY_NOLABEL)
92*2fe5d6deSMimi Zohar 		    || (status == INTEGRITY_NOXATTRS))
93*2fe5d6deSMimi Zohar 			cause = "missing-HMAC";
94*2fe5d6deSMimi Zohar 		else if (status == INTEGRITY_FAIL)
95*2fe5d6deSMimi Zohar 			cause = "invalid-HMAC";
96*2fe5d6deSMimi Zohar 		goto out;
97*2fe5d6deSMimi Zohar 	}
98*2fe5d6deSMimi Zohar 
99*2fe5d6deSMimi Zohar 	rc = memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE);
100*2fe5d6deSMimi Zohar 	if (rc) {
101*2fe5d6deSMimi Zohar 		status = INTEGRITY_FAIL;
102*2fe5d6deSMimi Zohar 		cause = "invalid-hash";
103*2fe5d6deSMimi Zohar 		print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE,
104*2fe5d6deSMimi Zohar 				     xattr_value, IMA_DIGEST_SIZE);
105*2fe5d6deSMimi Zohar 		print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE,
106*2fe5d6deSMimi Zohar 				     iint->digest, IMA_DIGEST_SIZE);
107*2fe5d6deSMimi Zohar 		goto out;
108*2fe5d6deSMimi Zohar 	}
109*2fe5d6deSMimi Zohar 	status = INTEGRITY_PASS;
110*2fe5d6deSMimi Zohar 	iint->flags |= IMA_APPRAISED;
111*2fe5d6deSMimi Zohar out:
112*2fe5d6deSMimi Zohar 	if (status != INTEGRITY_PASS) {
113*2fe5d6deSMimi Zohar 		if (ima_appraise & IMA_APPRAISE_FIX) {
114*2fe5d6deSMimi Zohar 			ima_fix_xattr(dentry, iint);
115*2fe5d6deSMimi Zohar 			status = INTEGRITY_PASS;
116*2fe5d6deSMimi Zohar 		}
117*2fe5d6deSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
118*2fe5d6deSMimi Zohar 				    op, cause, rc, 0);
119*2fe5d6deSMimi Zohar 	}
120*2fe5d6deSMimi Zohar 	iint->ima_status = status;
121*2fe5d6deSMimi Zohar 	return status;
122*2fe5d6deSMimi Zohar }
123*2fe5d6deSMimi Zohar 
124*2fe5d6deSMimi Zohar /*
125*2fe5d6deSMimi Zohar  * ima_update_xattr - update 'security.ima' hash value
126*2fe5d6deSMimi Zohar  */
127*2fe5d6deSMimi Zohar void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
128*2fe5d6deSMimi Zohar {
129*2fe5d6deSMimi Zohar 	struct dentry *dentry = file->f_dentry;
130*2fe5d6deSMimi Zohar 	int rc = 0;
131*2fe5d6deSMimi Zohar 
132*2fe5d6deSMimi Zohar 	rc = ima_collect_measurement(iint, file);
133*2fe5d6deSMimi Zohar 	if (rc < 0)
134*2fe5d6deSMimi Zohar 		return;
135*2fe5d6deSMimi Zohar 	ima_fix_xattr(dentry, iint);
136*2fe5d6deSMimi Zohar }
137*2fe5d6deSMimi Zohar 
138*2fe5d6deSMimi Zohar /**
139*2fe5d6deSMimi Zohar  * ima_inode_post_setattr - reflect file metadata changes
140*2fe5d6deSMimi Zohar  * @dentry: pointer to the affected dentry
141*2fe5d6deSMimi Zohar  *
142*2fe5d6deSMimi Zohar  * Changes to a dentry's metadata might result in needing to appraise.
143*2fe5d6deSMimi Zohar  *
144*2fe5d6deSMimi Zohar  * This function is called from notify_change(), which expects the caller
145*2fe5d6deSMimi Zohar  * to lock the inode's i_mutex.
146*2fe5d6deSMimi Zohar  */
147*2fe5d6deSMimi Zohar void ima_inode_post_setattr(struct dentry *dentry)
148*2fe5d6deSMimi Zohar {
149*2fe5d6deSMimi Zohar 	struct inode *inode = dentry->d_inode;
150*2fe5d6deSMimi Zohar 	struct integrity_iint_cache *iint;
151*2fe5d6deSMimi Zohar 	int must_appraise, rc;
152*2fe5d6deSMimi Zohar 
153*2fe5d6deSMimi Zohar 	if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
154*2fe5d6deSMimi Zohar 	    || !inode->i_op->removexattr)
155*2fe5d6deSMimi Zohar 		return;
156*2fe5d6deSMimi Zohar 
157*2fe5d6deSMimi Zohar 	must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
158*2fe5d6deSMimi Zohar 	iint = integrity_iint_find(inode);
159*2fe5d6deSMimi Zohar 	if (iint) {
160*2fe5d6deSMimi Zohar 		if (must_appraise)
161*2fe5d6deSMimi Zohar 			iint->flags |= IMA_APPRAISE;
162*2fe5d6deSMimi Zohar 		else
163*2fe5d6deSMimi Zohar 			iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED);
164*2fe5d6deSMimi Zohar 	}
165*2fe5d6deSMimi Zohar 	if (!must_appraise)
166*2fe5d6deSMimi Zohar 		rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
167*2fe5d6deSMimi Zohar 	return;
168*2fe5d6deSMimi Zohar }
169