xref: /linux/security/integrity/ima/ima_api.c (revision c7c8bb237fdbff932b5e431aebee5ce862ea07d1)
1 /*
2  * Copyright (C) 2008 IBM Corporation
3  *
4  * Author: Mimi Zohar <zohar@us.ibm.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation, version 2 of the
9  * License.
10  *
11  * File: ima_api.c
12  *	Implements must_appraise_or_measure, collect_measurement,
13  *	appraise_measurement, store_measurement and store_template.
14  */
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/file.h>
18 #include <linux/fs.h>
19 #include <linux/xattr.h>
20 #include <linux/evm.h>
21 #include "ima.h"
22 
23 static const char *IMA_TEMPLATE_NAME = "ima";
24 
25 /*
26  * ima_store_template - store ima template measurements
27  *
28  * Calculate the hash of a template entry, add the template entry
29  * to an ordered list of measurement entries maintained inside the kernel,
30  * and also update the aggregate integrity value (maintained inside the
31  * configured TPM PCR) over the hashes of the current list of measurement
32  * entries.
33  *
34  * Applications retrieve the current kernel-held measurement list through
35  * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
36  * TPM PCR (called quote) can be retrieved using a TPM user space library
37  * and is used to validate the measurement list.
38  *
39  * Returns 0 on success, error code otherwise
40  */
41 int ima_store_template(struct ima_template_entry *entry,
42 		       int violation, struct inode *inode)
43 {
44 	const char *op = "add_template_measure";
45 	const char *audit_cause = "hashing_error";
46 	int result;
47 	struct ima_digest_data hash;
48 
49 	memset(entry->digest, 0, sizeof(entry->digest));
50 	entry->template_name = IMA_TEMPLATE_NAME;
51 	entry->template_len = sizeof(entry->template);
52 
53 	if (!violation) {
54 		result = ima_calc_buffer_hash(&entry->template,
55 					      entry->template_len, &hash);
56 		if (result < 0) {
57 			integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
58 					    entry->template_name, op,
59 					    audit_cause, result, 0);
60 			return result;
61 		}
62 		memcpy(entry->digest, hash.digest, hash.length);
63 	}
64 	result = ima_add_template_entry(entry, violation, op, inode);
65 	return result;
66 }
67 
68 /*
69  * ima_add_violation - add violation to measurement list.
70  *
71  * Violations are flagged in the measurement list with zero hash values.
72  * By extending the PCR with 0xFF's instead of with zeroes, the PCR
73  * value is invalidated.
74  */
75 void ima_add_violation(struct inode *inode, const unsigned char *filename,
76 		       const char *op, const char *cause)
77 {
78 	struct ima_template_entry *entry;
79 	int violation = 1;
80 	int result;
81 
82 	/* can overflow, only indicator */
83 	atomic_long_inc(&ima_htable.violations);
84 
85 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
86 	if (!entry) {
87 		result = -ENOMEM;
88 		goto err_out;
89 	}
90 	memset(&entry->template, 0, sizeof(entry->template));
91 	strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
92 	result = ima_store_template(entry, violation, inode);
93 	if (result < 0)
94 		kfree(entry);
95 err_out:
96 	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
97 			    op, cause, result, 0);
98 }
99 
100 /**
101  * ima_get_action - appraise & measure decision based on policy.
102  * @inode: pointer to inode to measure
103  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
104  * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK)
105  *
106  * The policy is defined in terms of keypairs:
107  * 		subj=, obj=, type=, func=, mask=, fsmagic=
108  *	subj,obj, and type: are LSM specific.
109  * 	func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
110  * 	mask: contains the permission mask
111  *	fsmagic: hex value
112  *
113  * Returns IMA_MEASURE, IMA_APPRAISE mask.
114  *
115  */
116 int ima_get_action(struct inode *inode, int mask, int function)
117 {
118 	int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
119 
120 	if (!ima_appraise)
121 		flags &= ~IMA_APPRAISE;
122 
123 	return ima_match_policy(inode, function, mask, flags);
124 }
125 
126 int ima_must_measure(struct inode *inode, int mask, int function)
127 {
128 	return ima_match_policy(inode, function, mask, IMA_MEASURE);
129 }
130 
131 /*
132  * ima_collect_measurement - collect file measurement
133  *
134  * Calculate the file hash, if it doesn't already exist,
135  * storing the measurement and i_version in the iint.
136  *
137  * Must be called with iint->mutex held.
138  *
139  * Return 0 on success, error code otherwise
140  */
141 int ima_collect_measurement(struct integrity_iint_cache *iint,
142 			    struct file *file)
143 {
144 	struct inode *inode = file_inode(file);
145 	const char *filename = file->f_dentry->d_name.name;
146 	int result = 0;
147 
148 	if (!(iint->flags & IMA_COLLECTED)) {
149 		u64 i_version = file_inode(file)->i_version;
150 
151 		/* use default hash algorithm */
152 		iint->ima_hash.algo = ima_hash_algo;
153 		result = ima_calc_file_hash(file, &iint->ima_hash);
154 		if (!result) {
155 			iint->version = i_version;
156 			iint->flags |= IMA_COLLECTED;
157 		}
158 	}
159 	if (result)
160 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
161 				    filename, "collect_data", "failed",
162 				    result, 0);
163 	return result;
164 }
165 
166 /*
167  * ima_store_measurement - store file measurement
168  *
169  * Create an "ima" template and then store the template by calling
170  * ima_store_template.
171  *
172  * We only get here if the inode has not already been measured,
173  * but the measurement could already exist:
174  * 	- multiple copies of the same file on either the same or
175  *	  different filesystems.
176  *	- the inode was previously flushed as well as the iint info,
177  *	  containing the hashing info.
178  *
179  * Must be called with iint->mutex held.
180  */
181 void ima_store_measurement(struct integrity_iint_cache *iint,
182 			   struct file *file, const unsigned char *filename)
183 {
184 	const char *op = "add_template_measure";
185 	const char *audit_cause = "ENOMEM";
186 	int result = -ENOMEM;
187 	struct inode *inode = file_inode(file);
188 	struct ima_template_entry *entry;
189 	int violation = 0;
190 
191 	if (iint->flags & IMA_MEASURED)
192 		return;
193 
194 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
195 	if (!entry) {
196 		integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
197 				    op, audit_cause, result, 0);
198 		return;
199 	}
200 	memset(&entry->template, 0, sizeof(entry->template));
201 	if (iint->ima_hash.algo != ima_hash_algo) {
202 		struct ima_digest_data hash;
203 
204 		hash.algo = ima_hash_algo;
205 		result = ima_calc_file_hash(file, &hash);
206 		if (result)
207 			integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
208 					    filename, "collect_data", "failed",
209 					    result, 0);
210 		else
211 			memcpy(entry->template.digest, hash.digest,
212 			       hash.length);
213 	} else
214 		memcpy(entry->template.digest, iint->ima_hash.digest,
215 		       iint->ima_hash.length);
216 	strcpy(entry->template.file_name,
217 	       (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
218 	       file->f_dentry->d_name.name : filename);
219 
220 	result = ima_store_template(entry, violation, inode);
221 	if (!result || result == -EEXIST)
222 		iint->flags |= IMA_MEASURED;
223 	if (result < 0)
224 		kfree(entry);
225 }
226 
227 void ima_audit_measurement(struct integrity_iint_cache *iint,
228 			   const unsigned char *filename)
229 {
230 	struct audit_buffer *ab;
231 	char hash[(iint->ima_hash.length * 2) + 1];
232 	int i;
233 
234 	if (iint->flags & IMA_AUDITED)
235 		return;
236 
237 	for (i = 0; i < iint->ima_hash.length; i++)
238 		hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]);
239 	hash[i * 2] = '\0';
240 
241 	ab = audit_log_start(current->audit_context, GFP_KERNEL,
242 			     AUDIT_INTEGRITY_RULE);
243 	if (!ab)
244 		return;
245 
246 	audit_log_format(ab, "file=");
247 	audit_log_untrustedstring(ab, filename);
248 	audit_log_format(ab, " hash=");
249 	audit_log_untrustedstring(ab, hash);
250 
251 	audit_log_task_info(ab, current);
252 	audit_log_end(ab);
253 
254 	iint->flags |= IMA_AUDITED;
255 }
256 
257 const char *ima_d_path(struct path *path, char **pathbuf)
258 {
259 	char *pathname = NULL;
260 
261 	/* We will allow 11 spaces for ' (deleted)' to be appended */
262 	*pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
263 	if (*pathbuf) {
264 		pathname = d_path(path, *pathbuf, PATH_MAX + 11);
265 		if (IS_ERR(pathname)) {
266 			kfree(*pathbuf);
267 			*pathbuf = NULL;
268 			pathname = NULL;
269 		}
270 	}
271 	return pathname;
272 }
273