ima: pass full xattr with the signature
[deliverable/linux.git] / security / integrity / ima / ima_api.c
CommitLineData
3323eec9
MZ
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
2fe5d6de
MZ
12 * Implements must_appraise_or_measure, collect_measurement,
13 * appraise_measurement, store_measurement and store_template.
3323eec9
MZ
14 */
15#include <linux/module.h>
5a0e3ad6 16#include <linux/slab.h>
2fe5d6de
MZ
17#include <linux/file.h>
18#include <linux/fs.h>
19#include <linux/xattr.h>
20#include <linux/evm.h>
3323eec9 21#include "ima.h"
2fe5d6de 22
523979ad 23static const char *IMA_TEMPLATE_NAME = "ima";
3323eec9
MZ
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 */
41int 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;
c7c8bb23 47 struct ima_digest_data hash;
3323eec9
MZ
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) {
50af5544 54 result = ima_calc_buffer_hash(&entry->template,
c7c8bb23 55 entry->template_len, &hash);
3323eec9
MZ
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 }
c7c8bb23 62 memcpy(entry->digest, hash.digest, hash.length);
3323eec9
MZ
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 */
75void 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);
95err_out:
96 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
97 op, cause, result, 0);
98}
99
100/**
d9d300cd 101 * ima_get_action - appraise & measure decision based on policy.
3323eec9
MZ
102 * @inode: pointer to inode to measure
103 * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
16cac49f 104 * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK)
3323eec9
MZ
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.
16cac49f 109 * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
3323eec9
MZ
110 * mask: contains the permission mask
111 * fsmagic: hex value
112 *
2fe5d6de
MZ
113 * Returns IMA_MEASURE, IMA_APPRAISE mask.
114 *
115 */
d9d300cd 116int ima_get_action(struct inode *inode, int mask, int function)
3323eec9 117{
e7c568e0 118 int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
2fe5d6de
MZ
119
120 if (!ima_appraise)
121 flags &= ~IMA_APPRAISE;
122
123 return ima_match_policy(inode, function, mask, flags);
124}
3323eec9 125
2fe5d6de
MZ
126int ima_must_measure(struct inode *inode, int mask, int function)
127{
128 return ima_match_policy(inode, function, mask, IMA_MEASURE);
3323eec9
MZ
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 */
f381c272 141int ima_collect_measurement(struct integrity_iint_cache *iint,
d3634d0f
DK
142 struct file *file,
143 struct evm_ima_xattr_data **xattr_value,
144 int *xattr_len)
3323eec9 145{
496ad9aa 146 struct inode *inode = file_inode(file);
2fe5d6de
MZ
147 const char *filename = file->f_dentry->d_name.name;
148 int result = 0;
3323eec9 149
d3634d0f
DK
150 if (xattr_value)
151 *xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
152
2fe5d6de 153 if (!(iint->flags & IMA_COLLECTED)) {
496ad9aa 154 u64 i_version = file_inode(file)->i_version;
3323eec9 155
c7c8bb23
DK
156 /* use default hash algorithm */
157 iint->ima_hash.algo = ima_hash_algo;
d3634d0f
DK
158
159 if (xattr_value)
160 ima_get_hash_algo(*xattr_value, *xattr_len,
161 &iint->ima_hash);
162
c7c8bb23 163 result = ima_calc_file_hash(file, &iint->ima_hash);
2fe5d6de 164 if (!result) {
3323eec9 165 iint->version = i_version;
2fe5d6de
MZ
166 iint->flags |= IMA_COLLECTED;
167 }
3323eec9 168 }
2fe5d6de
MZ
169 if (result)
170 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
171 filename, "collect_data", "failed",
172 result, 0);
3323eec9
MZ
173 return result;
174}
175
176/*
177 * ima_store_measurement - store file measurement
178 *
179 * Create an "ima" template and then store the template by calling
180 * ima_store_template.
181 *
182 * We only get here if the inode has not already been measured,
183 * but the measurement could already exist:
184 * - multiple copies of the same file on either the same or
185 * different filesystems.
186 * - the inode was previously flushed as well as the iint info,
187 * containing the hashing info.
188 *
189 * Must be called with iint->mutex held.
190 */
f381c272
MZ
191void ima_store_measurement(struct integrity_iint_cache *iint,
192 struct file *file, const unsigned char *filename)
3323eec9
MZ
193{
194 const char *op = "add_template_measure";
195 const char *audit_cause = "ENOMEM";
196 int result = -ENOMEM;
496ad9aa 197 struct inode *inode = file_inode(file);
3323eec9
MZ
198 struct ima_template_entry *entry;
199 int violation = 0;
200
2fe5d6de
MZ
201 if (iint->flags & IMA_MEASURED)
202 return;
203
3323eec9
MZ
204 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
205 if (!entry) {
206 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
207 op, audit_cause, result, 0);
208 return;
209 }
210 memset(&entry->template, 0, sizeof(entry->template));
c7c8bb23
DK
211 if (iint->ima_hash.algo != ima_hash_algo) {
212 struct ima_digest_data hash;
213
214 hash.algo = ima_hash_algo;
215 result = ima_calc_file_hash(file, &hash);
216 if (result)
217 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
218 filename, "collect_data", "failed",
219 result, 0);
220 else
221 memcpy(entry->template.digest, hash.digest,
222 hash.length);
223 } else
224 memcpy(entry->template.digest, iint->ima_hash.digest,
225 iint->ima_hash.length);
08e1b76a
MZ
226 strcpy(entry->template.file_name,
227 (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
228 file->f_dentry->d_name.name : filename);
3323eec9
MZ
229
230 result = ima_store_template(entry, violation, inode);
45fae749 231 if (!result || result == -EEXIST)
3323eec9 232 iint->flags |= IMA_MEASURED;
45fae749 233 if (result < 0)
3323eec9
MZ
234 kfree(entry);
235}
e7c568e0
PM
236
237void ima_audit_measurement(struct integrity_iint_cache *iint,
238 const unsigned char *filename)
239{
240 struct audit_buffer *ab;
c7c8bb23 241 char hash[(iint->ima_hash.length * 2) + 1];
e7c568e0
PM
242 int i;
243
244 if (iint->flags & IMA_AUDITED)
245 return;
246
c7c8bb23
DK
247 for (i = 0; i < iint->ima_hash.length; i++)
248 hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]);
e7c568e0
PM
249 hash[i * 2] = '\0';
250
251 ab = audit_log_start(current->audit_context, GFP_KERNEL,
252 AUDIT_INTEGRITY_RULE);
253 if (!ab)
254 return;
255
256 audit_log_format(ab, "file=");
257 audit_log_untrustedstring(ab, filename);
258 audit_log_format(ab, " hash=");
259 audit_log_untrustedstring(ab, hash);
260
261 audit_log_task_info(ab, current);
262 audit_log_end(ab);
263
264 iint->flags |= IMA_AUDITED;
265}
ea1046d4
DK
266
267const char *ima_d_path(struct path *path, char **pathbuf)
268{
269 char *pathname = NULL;
270
271 /* We will allow 11 spaces for ' (deleted)' to be appended */
272 *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
273 if (*pathbuf) {
274 pathname = d_path(path, *pathbuf, PATH_MAX + 11);
275 if (IS_ERR(pathname)) {
276 kfree(*pathbuf);
277 *pathbuf = NULL;
278 pathname = NULL;
279 }
280 }
281 return pathname;
282}
This page took 0.203357 seconds and 5 git commands to generate.