blob: 29dd43de823a53c9c5d07008af34477d3a1f415e [file] [log] [blame]
Mimi Zohar3323eec2009-02-04 09:06:58 -05001/*
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
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -050012 * Implements must_appraise_or_measure, collect_measurement,
13 * appraise_measurement, store_measurement and store_template.
Mimi Zohar3323eec2009-02-04 09:06:58 -050014 */
15#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -050017#include <linux/file.h>
18#include <linux/fs.h>
19#include <linux/xattr.h>
20#include <linux/evm.h>
Dmitry Kasatkinea593992013-06-07 12:16:24 +020021#include <crypto/hash_info.h>
Mimi Zohar3323eec2009-02-04 09:06:58 -050022#include "ima.h"
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -050023
Mimi Zohar523979a2009-02-11 11:12:28 -050024static const char *IMA_TEMPLATE_NAME = "ima";
Mimi Zohar3323eec2009-02-04 09:06:58 -050025
26/*
Roberto Sassu7bc5f442013-06-07 12:16:28 +020027 * ima_alloc_init_template - create and initialize a new template entry
28 */
29int ima_alloc_init_template(struct integrity_iint_cache *iint,
30 struct file *file, const unsigned char *filename,
31 struct ima_template_entry **entry)
32{
33 struct ima_template_entry *e;
34 int result = 0;
35
36 e = kzalloc(sizeof(**entry), GFP_NOFS);
37 if (!e)
38 return -ENOMEM;
39
40 memset(&(e)->template, 0, sizeof(e->template));
41 if (!iint) /* IMA measurement violation entry */
42 goto out;
43
44 if (iint->ima_hash->algo != ima_hash_algo) {
45 struct inode *inode;
46 struct {
47 struct ima_digest_data hdr;
48 char digest[IMA_MAX_DIGEST_SIZE];
49 } hash;
50
51 if (!file) {
52 result = -EINVAL;
53 goto out_free;
54 }
55
56 inode = file_inode(file);
57 hash.hdr.algo = ima_hash_algo;
58 hash.hdr.length = SHA1_DIGEST_SIZE;
59 result = ima_calc_file_hash(file, &hash.hdr);
60 if (result) {
61 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
62 filename, "collect_data",
63 "failed", result, 0);
64 goto out_free;
65 } else
66 memcpy(e->template.digest, hash.hdr.digest,
67 hash.hdr.length);
68 } else
69 memcpy(e->template.digest, iint->ima_hash->digest,
70 iint->ima_hash->length);
71out:
72 strcpy(e->template.file_name,
73 (strlen(filename) > IMA_EVENT_NAME_LEN_MAX && file != NULL) ?
74 file->f_dentry->d_name.name : filename);
75 *entry = e;
76 return 0;
77out_free:
78 kfree(e);
79 return result;
80}
81
82/*
Mimi Zohar3323eec2009-02-04 09:06:58 -050083 * ima_store_template - store ima template measurements
84 *
85 * Calculate the hash of a template entry, add the template entry
86 * to an ordered list of measurement entries maintained inside the kernel,
87 * and also update the aggregate integrity value (maintained inside the
88 * configured TPM PCR) over the hashes of the current list of measurement
89 * entries.
90 *
91 * Applications retrieve the current kernel-held measurement list through
92 * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
93 * TPM PCR (called quote) can be retrieved using a TPM user space library
94 * and is used to validate the measurement list.
95 *
96 * Returns 0 on success, error code otherwise
97 */
98int ima_store_template(struct ima_template_entry *entry,
Roberto Sassu9803d412013-06-07 12:16:27 +020099 int violation, struct inode *inode,
100 const unsigned char *filename)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500101{
102 const char *op = "add_template_measure";
103 const char *audit_cause = "hashing_error";
104 int result;
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300105 struct {
106 struct ima_digest_data hdr;
Mimi Zohar140d8022013-03-11 20:29:47 -0400107 char digest[TPM_DIGEST_SIZE];
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300108 } hash;
Mimi Zohar3323eec2009-02-04 09:06:58 -0500109
110 memset(entry->digest, 0, sizeof(entry->digest));
111 entry->template_name = IMA_TEMPLATE_NAME;
112 entry->template_len = sizeof(entry->template);
113
114 if (!violation) {
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200115 /* this function uses default algo */
116 hash.hdr.algo = HASH_ALGO_SHA1;
Dmitry Kasatkin50af5542012-05-14 14:13:56 +0300117 result = ima_calc_buffer_hash(&entry->template,
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300118 entry->template_len, &hash.hdr);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500119 if (result < 0) {
120 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
121 entry->template_name, op,
122 audit_cause, result, 0);
123 return result;
124 }
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300125 memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500126 }
Roberto Sassu9803d412013-06-07 12:16:27 +0200127 result = ima_add_template_entry(entry, violation, op, inode, filename);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500128 return result;
129}
130
131/*
132 * ima_add_violation - add violation to measurement list.
133 *
134 * Violations are flagged in the measurement list with zero hash values.
135 * By extending the PCR with 0xFF's instead of with zeroes, the PCR
136 * value is invalidated.
137 */
Roberto Sassu7d802a22013-06-07 12:16:26 +0200138void ima_add_violation(struct file *file, const unsigned char *filename,
Mimi Zohar3323eec2009-02-04 09:06:58 -0500139 const char *op, const char *cause)
140{
141 struct ima_template_entry *entry;
Roberto Sassu7d802a22013-06-07 12:16:26 +0200142 struct inode *inode = file->f_dentry->d_inode;
Mimi Zohar3323eec2009-02-04 09:06:58 -0500143 int violation = 1;
144 int result;
145
146 /* can overflow, only indicator */
147 atomic_long_inc(&ima_htable.violations);
148
Roberto Sassu7bc5f442013-06-07 12:16:28 +0200149 result = ima_alloc_init_template(NULL, file, filename, &entry);
150 if (result < 0) {
Mimi Zohar3323eec2009-02-04 09:06:58 -0500151 result = -ENOMEM;
152 goto err_out;
153 }
Roberto Sassu9803d412013-06-07 12:16:27 +0200154 result = ima_store_template(entry, violation, inode, filename);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500155 if (result < 0)
156 kfree(entry);
157err_out:
158 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
159 op, cause, result, 0);
160}
161
162/**
Dmitry Kasatkind9d300c2012-06-27 11:26:14 +0300163 * ima_get_action - appraise & measure decision based on policy.
Mimi Zohar3323eec2009-02-04 09:06:58 -0500164 * @inode: pointer to inode to measure
165 * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
Mimi Zohar16cac492012-12-13 11:15:04 -0500166 * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500167 *
168 * The policy is defined in terms of keypairs:
169 * subj=, obj=, type=, func=, mask=, fsmagic=
170 * subj,obj, and type: are LSM specific.
Mimi Zohar16cac492012-12-13 11:15:04 -0500171 * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
Mimi Zohar3323eec2009-02-04 09:06:58 -0500172 * mask: contains the permission mask
173 * fsmagic: hex value
174 *
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500175 * Returns IMA_MEASURE, IMA_APPRAISE mask.
176 *
177 */
Dmitry Kasatkind9d300c2012-06-27 11:26:14 +0300178int ima_get_action(struct inode *inode, int mask, int function)
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500179{
Peter Moodye7c568e2012-06-14 10:04:36 -0700180 int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500181
182 if (!ima_appraise)
183 flags &= ~IMA_APPRAISE;
184
185 return ima_match_policy(inode, function, mask, flags);
186}
187
Mimi Zohar1adace92011-02-22 10:19:43 -0500188int ima_must_measure(struct inode *inode, int mask, int function)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500189{
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500190 return ima_match_policy(inode, function, mask, IMA_MEASURE);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500191}
192
193/*
194 * ima_collect_measurement - collect file measurement
195 *
196 * Calculate the file hash, if it doesn't already exist,
197 * storing the measurement and i_version in the iint.
198 *
199 * Must be called with iint->mutex held.
200 *
201 * Return 0 on success, error code otherwise
202 */
Mimi Zoharf381c272011-03-09 14:13:22 -0500203int ima_collect_measurement(struct integrity_iint_cache *iint,
Dmitry Kasatkind3634d02013-04-25 10:44:04 +0300204 struct file *file,
205 struct evm_ima_xattr_data **xattr_value,
206 int *xattr_len)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500207{
Al Viro496ad9a2013-01-23 17:07:38 -0500208 struct inode *inode = file_inode(file);
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500209 const char *filename = file->f_dentry->d_name.name;
210 int result = 0;
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300211 struct {
212 struct ima_digest_data hdr;
213 char digest[IMA_MAX_DIGEST_SIZE];
214 } hash;
Mimi Zohar3323eec2009-02-04 09:06:58 -0500215
Dmitry Kasatkind3634d02013-04-25 10:44:04 +0300216 if (xattr_value)
217 *xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
218
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500219 if (!(iint->flags & IMA_COLLECTED)) {
Al Viro496ad9a2013-01-23 17:07:38 -0500220 u64 i_version = file_inode(file)->i_version;
Mimi Zohar3323eec2009-02-04 09:06:58 -0500221
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300222 /* use default hash algorithm */
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300223 hash.hdr.algo = ima_hash_algo;
Dmitry Kasatkind3634d02013-04-25 10:44:04 +0300224
225 if (xattr_value)
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300226 ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr);
Dmitry Kasatkind3634d02013-04-25 10:44:04 +0300227
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300228 result = ima_calc_file_hash(file, &hash.hdr);
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500229 if (!result) {
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300230 int length = sizeof(hash.hdr) + hash.hdr.length;
231 void *tmpbuf = krealloc(iint->ima_hash, length,
232 GFP_NOFS);
233 if (tmpbuf) {
234 iint->ima_hash = tmpbuf;
235 memcpy(iint->ima_hash, &hash, length);
236 iint->version = i_version;
237 iint->flags |= IMA_COLLECTED;
238 } else
239 result = -ENOMEM;
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500240 }
Mimi Zohar3323eec2009-02-04 09:06:58 -0500241 }
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500242 if (result)
243 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
244 filename, "collect_data", "failed",
245 result, 0);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500246 return result;
247}
248
249/*
250 * ima_store_measurement - store file measurement
251 *
252 * Create an "ima" template and then store the template by calling
253 * ima_store_template.
254 *
255 * We only get here if the inode has not already been measured,
256 * but the measurement could already exist:
257 * - multiple copies of the same file on either the same or
258 * different filesystems.
259 * - the inode was previously flushed as well as the iint info,
260 * containing the hashing info.
261 *
262 * Must be called with iint->mutex held.
263 */
Mimi Zoharf381c272011-03-09 14:13:22 -0500264void ima_store_measurement(struct integrity_iint_cache *iint,
265 struct file *file, const unsigned char *filename)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500266{
267 const char *op = "add_template_measure";
268 const char *audit_cause = "ENOMEM";
269 int result = -ENOMEM;
Al Viro496ad9a2013-01-23 17:07:38 -0500270 struct inode *inode = file_inode(file);
Mimi Zohar3323eec2009-02-04 09:06:58 -0500271 struct ima_template_entry *entry;
272 int violation = 0;
273
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500274 if (iint->flags & IMA_MEASURED)
275 return;
276
Roberto Sassu7bc5f442013-06-07 12:16:28 +0200277 result = ima_alloc_init_template(iint, file, filename, &entry);
278 if (result < 0) {
Mimi Zohar3323eec2009-02-04 09:06:58 -0500279 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
280 op, audit_cause, result, 0);
281 return;
282 }
Mimi Zohar3323eec2009-02-04 09:06:58 -0500283
Roberto Sassu9803d412013-06-07 12:16:27 +0200284 result = ima_store_template(entry, violation, inode, filename);
Roberto Sassu45fae742011-12-19 15:57:27 +0100285 if (!result || result == -EEXIST)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500286 iint->flags |= IMA_MEASURED;
Roberto Sassu45fae742011-12-19 15:57:27 +0100287 if (result < 0)
Mimi Zohar3323eec2009-02-04 09:06:58 -0500288 kfree(entry);
289}
Peter Moodye7c568e2012-06-14 10:04:36 -0700290
291void ima_audit_measurement(struct integrity_iint_cache *iint,
292 const unsigned char *filename)
293{
294 struct audit_buffer *ab;
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300295 char hash[(iint->ima_hash->length * 2) + 1];
Peter Moodye7c568e2012-06-14 10:04:36 -0700296 int i;
297
298 if (iint->flags & IMA_AUDITED)
299 return;
300
Dmitry Kasatkina35c3fb2013-04-25 10:44:04 +0300301 for (i = 0; i < iint->ima_hash->length; i++)
302 hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
Peter Moodye7c568e2012-06-14 10:04:36 -0700303 hash[i * 2] = '\0';
304
305 ab = audit_log_start(current->audit_context, GFP_KERNEL,
306 AUDIT_INTEGRITY_RULE);
307 if (!ab)
308 return;
309
310 audit_log_format(ab, "file=");
311 audit_log_untrustedstring(ab, filename);
312 audit_log_format(ab, " hash=");
313 audit_log_untrustedstring(ab, hash);
314
315 audit_log_task_info(ab, current);
316 audit_log_end(ab);
317
318 iint->flags |= IMA_AUDITED;
319}
Dmitry Kasatkinea1046d2012-09-04 00:40:17 +0300320
321const char *ima_d_path(struct path *path, char **pathbuf)
322{
323 char *pathname = NULL;
324
325 /* We will allow 11 spaces for ' (deleted)' to be appended */
326 *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
327 if (*pathbuf) {
328 pathname = d_path(path, *pathbuf, PATH_MAX + 11);
329 if (IS_ERR(pathname)) {
330 kfree(*pathbuf);
331 *pathbuf = NULL;
332 pathname = NULL;
333 }
334 }
335 return pathname;
336}