aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_main.c
diff options
context:
space:
mode:
authorMimi Zohar <zohar@linux.vnet.ibm.com>2009-02-04 09:06:58 -0500
committerJames Morris <jmorris@namei.org>2009-02-05 17:05:30 -0500
commit3323eec921efd815178a23107ab63588c605c0b2 (patch)
treebc9e9714ac4881ebc515c1bd155674c52c356d6a /security/integrity/ima/ima_main.c
parent6146f0d5e47ca4047ffded0fb79b6c25359b386c (diff)
integrity: IMA as an integrity service provider
IMA provides hardware (TPM) based measurement and attestation for file measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the integrity_bprm_check, integrity_path_check and integrity_file_mmap hooks), and commits the measurements to the TPM. Once added to the TPM, measurements can not be removed. In addition, IMA maintains a list of these file measurements, which can be used to validate the aggregate value stored in the TPM. The TPM can sign these measurements, and thus the system can prove, to itself and to a third party, the system's integrity in a way that cannot be circumvented by malicious or compromised software. - alloc ima_template_entry before calling ima_store_template() - log ima_add_boot_aggregate() failure - removed unused IMA_TEMPLATE_NAME_LEN - replaced hard coded string length with #define name Signed-off-by: Mimi Zohar <zohar@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r--security/integrity/ima/ima_main.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
new file mode 100644
index 000000000000..53cee4c512ce
--- /dev/null
+++ b/security/integrity/ima/ima_main.c
@@ -0,0 +1,280 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Reiner Sailer <sailer@watson.ibm.com>
6 * Serge Hallyn <serue@us.ibm.com>
7 * Kylene Hall <kylene@us.ibm.com>
8 * Mimi Zohar <zohar@us.ibm.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, version 2 of the
13 * License.
14 *
15 * File: ima_main.c
16 * implements the IMA hooks: ima_bprm_check, ima_file_mmap,
17 * and ima_path_check.
18 */
19#include <linux/module.h>
20#include <linux/file.h>
21#include <linux/binfmts.h>
22#include <linux/mount.h>
23#include <linux/mman.h>
24
25#include "ima.h"
26
27int ima_initialized;
28
29char *ima_hash = "sha1";
30static int __init hash_setup(char *str)
31{
32 const char *op = "hash_setup";
33 const char *hash = "sha1";
34 int result = 0;
35 int audit_info = 0;
36
37 if (strncmp(str, "md5", 3) == 0) {
38 hash = "md5";
39 ima_hash = str;
40 } else if (strncmp(str, "sha1", 4) != 0) {
41 hash = "invalid_hash_type";
42 result = 1;
43 }
44 integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
45 result, audit_info);
46 return 1;
47}
48__setup("ima_hash=", hash_setup);
49
50/**
51 * ima_file_free - called on __fput()
52 * @file: pointer to file structure being freed
53 *
54 * Flag files that changed, based on i_version;
55 * and decrement the iint readcount/writecount.
56 */
57void ima_file_free(struct file *file)
58{
59 struct inode *inode = file->f_dentry->d_inode;
60 struct ima_iint_cache *iint;
61
62 if (!ima_initialized || !S_ISREG(inode->i_mode))
63 return;
64 iint = ima_iint_find_get(inode);
65 if (!iint)
66 return;
67
68 mutex_lock(&iint->mutex);
69 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
70 iint->readcount--;
71
72 if (file->f_mode & FMODE_WRITE) {
73 iint->writecount--;
74 if (iint->writecount == 0) {
75 if (iint->version != inode->i_version)
76 iint->flags &= ~IMA_MEASURED;
77 }
78 }
79 mutex_unlock(&iint->mutex);
80 kref_put(&iint->refcount, iint_free);
81}
82
83/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
84 *
85 * When opening a file for read, if the file is already open for write,
86 * the file could change, resulting in a file measurement error.
87 *
88 * Opening a file for write, if the file is already open for read, results
89 * in a time of measure, time of use (ToMToU) error.
90 *
91 * In either case invalidate the PCR.
92 */
93enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
94static void ima_read_write_check(enum iint_pcr_error error,
95 struct ima_iint_cache *iint,
96 struct inode *inode,
97 const unsigned char *filename)
98{
99 switch (error) {
100 case TOMTOU:
101 if (iint->readcount > 0)
102 ima_add_violation(inode, filename, "invalid_pcr",
103 "ToMToU");
104 break;
105 case OPEN_WRITERS:
106 if (iint->writecount > 0)
107 ima_add_violation(inode, filename, "invalid_pcr",
108 "open_writers");
109 break;
110 }
111}
112
113static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
114 const unsigned char *filename)
115{
116 int rc = 0;
117
118 if (IS_ERR(file)) {
119 pr_info("%s dentry_open failed\n", filename);
120 return rc;
121 }
122 iint->readcount++;
123
124 rc = ima_collect_measurement(iint, file);
125 if (!rc)
126 ima_store_measurement(iint, file, filename);
127 return rc;
128}
129
130/**
131 * ima_path_check - based on policy, collect/store measurement.
132 * @path: contains a pointer to the path to be measured
133 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
134 *
135 * Measure the file being open for readonly, based on the
136 * ima_must_measure() policy decision.
137 *
138 * Keep read/write counters for all files, but only
139 * invalidate the PCR for measured files:
140 * - Opening a file for write when already open for read,
141 * results in a time of measure, time of use (ToMToU) error.
142 * - Opening a file for read when already open for write,
143 * could result in a file measurement error.
144 *
145 * Return 0 on success, an error code on failure.
146 * (Based on the results of appraise_measurement().)
147 */
148int ima_path_check(struct path *path, int mask)
149{
150 struct inode *inode = path->dentry->d_inode;
151 struct ima_iint_cache *iint;
152 struct file *file = NULL;
153 int rc;
154
155 if (!ima_initialized || !S_ISREG(inode->i_mode))
156 return 0;
157 iint = ima_iint_find_insert_get(inode);
158 if (!iint)
159 return 0;
160
161 mutex_lock(&iint->mutex);
162 if ((mask & MAY_WRITE) || (mask == 0))
163 iint->writecount++;
164 else if (mask & (MAY_READ | MAY_EXEC))
165 iint->readcount++;
166
167 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
168 if (rc < 0)
169 goto out;
170
171 if ((mask & MAY_WRITE) || (mask == 0))
172 ima_read_write_check(TOMTOU, iint, inode,
173 path->dentry->d_name.name);
174
175 if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
176 goto out;
177
178 ima_read_write_check(OPEN_WRITERS, iint, inode,
179 path->dentry->d_name.name);
180 if (!(iint->flags & IMA_MEASURED)) {
181 struct dentry *dentry = dget(path->dentry);
182 struct vfsmount *mnt = mntget(path->mnt);
183
184 file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
185 rc = get_path_measurement(iint, file, dentry->d_name.name);
186 }
187out:
188 mutex_unlock(&iint->mutex);
189 if (file)
190 fput(file);
191 kref_put(&iint->refcount, iint_free);
192 return 0;
193}
194
195static int process_measurement(struct file *file, const unsigned char *filename,
196 int mask, int function)
197{
198 struct inode *inode = file->f_dentry->d_inode;
199 struct ima_iint_cache *iint;
200 int rc;
201
202 if (!ima_initialized || !S_ISREG(inode->i_mode))
203 return 0;
204 iint = ima_iint_find_insert_get(inode);
205 if (!iint)
206 return -ENOMEM;
207
208 mutex_lock(&iint->mutex);
209 rc = ima_must_measure(iint, inode, mask, function);
210 if (rc != 0)
211 goto out;
212
213 rc = ima_collect_measurement(iint, file);
214 if (!rc)
215 ima_store_measurement(iint, file, filename);
216out:
217 mutex_unlock(&iint->mutex);
218 kref_put(&iint->refcount, iint_free);
219 return rc;
220}
221
222/**
223 * ima_file_mmap - based on policy, collect/store measurement.
224 * @file: pointer to the file to be measured (May be NULL)
225 * @prot: contains the protection that will be applied by the kernel.
226 *
227 * Measure files being mmapped executable based on the ima_must_measure()
228 * policy decision.
229 *
230 * Return 0 on success, an error code on failure.
231 * (Based on the results of appraise_measurement().)
232 */
233int ima_file_mmap(struct file *file, unsigned long prot)
234{
235 int rc;
236
237 if (!file)
238 return 0;
239 if (prot & PROT_EXEC)
240 rc = process_measurement(file, file->f_dentry->d_name.name,
241 MAY_EXEC, FILE_MMAP);
242 return 0;
243}
244
245/**
246 * ima_bprm_check - based on policy, collect/store measurement.
247 * @bprm: contains the linux_binprm structure
248 *
249 * The OS protects against an executable file, already open for write,
250 * from being executed in deny_write_access() and an executable file,
251 * already open for execute, from being modified in get_write_access().
252 * So we can be certain that what we verify and measure here is actually
253 * what is being executed.
254 *
255 * Return 0 on success, an error code on failure.
256 * (Based on the results of appraise_measurement().)
257 */
258int ima_bprm_check(struct linux_binprm *bprm)
259{
260 int rc;
261
262 rc = process_measurement(bprm->file, bprm->filename,
263 MAY_EXEC, BPRM_CHECK);
264 return 0;
265}
266
267static int __init init_ima(void)
268{
269 int error;
270
271 ima_iintcache_init();
272 error = ima_init();
273 ima_initialized = 1;
274 return error;
275}
276
277late_initcall(init_ima); /* Start IMA after the TPM is available */
278
279MODULE_DESCRIPTION("Integrity Measurement Architecture");
280MODULE_LICENSE("GPL");