aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/integrity/ima/Makefile2
-rw-r--r--security/integrity/ima/ima.h5
-rw-r--r--security/integrity/ima/ima_fs.c296
-rw-r--r--security/integrity/ima/ima_init.c8
-rw-r--r--security/integrity/ima/ima_main.c5
5 files changed, 314 insertions, 2 deletions
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 9d6bf973b9be..787c4cb916cd 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -5,5 +5,5 @@
5 5
6obj-$(CONFIG_IMA) += ima.o 6obj-$(CONFIG_IMA) += ima.o
7 7
8ima-y := ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ 8ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
9 ima_policy.o ima_iint.o ima_audit.o 9 ima_policy.o ima_iint.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index bfa72ed41b9b..9c280cc73004 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -67,6 +67,9 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
67/* Internal IMA function definitions */ 67/* Internal IMA function definitions */
68void ima_iintcache_init(void); 68void ima_iintcache_init(void);
69int ima_init(void); 69int ima_init(void);
70void ima_cleanup(void);
71int ima_fs_init(void);
72void ima_fs_cleanup(void);
70int ima_add_template_entry(struct ima_template_entry *entry, int violation, 73int ima_add_template_entry(struct ima_template_entry *entry, int violation,
71 const char *op, struct inode *inode); 74 const char *op, struct inode *inode);
72int ima_calc_hash(struct file *file, char *digest); 75int ima_calc_hash(struct file *file, char *digest);
@@ -115,6 +118,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
115 const unsigned char *filename); 118 const unsigned char *filename);
116int ima_store_template(struct ima_template_entry *entry, int violation, 119int ima_store_template(struct ima_template_entry *entry, int violation,
117 struct inode *inode); 120 struct inode *inode);
121void ima_template_show(struct seq_file *m, void *e,
122 enum ima_show_type show);
118 123
119/* radix tree calls to lookup, insert, delete 124/* radix tree calls to lookup, insert, delete
120 * integrity data associated with an inode. 125 * integrity data associated with an inode.
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
new file mode 100644
index 000000000000..4f25be768b50
--- /dev/null
+++ b/security/integrity/ima/ima_fs.c
@@ -0,0 +1,296 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Kylene Hall <kjhall@us.ibm.com>
6 * Reiner Sailer <sailer@us.ibm.com>
7 * Mimi Zohar <zohar@us.ibm.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 *
14 * File: ima_fs.c
15 * implemenents security file system for reporting
16 * current measurement list and IMA statistics
17 */
18#include <linux/module.h>
19#include <linux/seq_file.h>
20#include <linux/rculist.h>
21#include <linux/rcupdate.h>
22
23#include "ima.h"
24
25#define TMPBUFLEN 12
26static ssize_t ima_show_htable_value(char __user *buf, size_t count,
27 loff_t *ppos, atomic_long_t *val)
28{
29 char tmpbuf[TMPBUFLEN];
30 ssize_t len;
31
32 len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val));
33 return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
34}
35
36static ssize_t ima_show_htable_violations(struct file *filp,
37 char __user *buf,
38 size_t count, loff_t *ppos)
39{
40 return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
41}
42
43static struct file_operations ima_htable_violations_ops = {
44 .read = ima_show_htable_violations
45};
46
47static ssize_t ima_show_measurements_count(struct file *filp,
48 char __user *buf,
49 size_t count, loff_t *ppos)
50{
51 return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
52
53}
54
55static struct file_operations ima_measurements_count_ops = {
56 .read = ima_show_measurements_count
57};
58
59/* returns pointer to hlist_node */
60static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
61{
62 loff_t l = *pos;
63 struct ima_queue_entry *qe;
64
65 /* we need a lock since pos could point beyond last element */
66 rcu_read_lock();
67 list_for_each_entry_rcu(qe, &ima_measurements, later) {
68 if (!l--) {
69 rcu_read_unlock();
70 return qe;
71 }
72 }
73 rcu_read_unlock();
74 return NULL;
75}
76
77static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
78{
79 struct ima_queue_entry *qe = v;
80
81 /* lock protects when reading beyond last element
82 * against concurrent list-extension
83 */
84 rcu_read_lock();
85 qe = list_entry(rcu_dereference(qe->later.next),
86 struct ima_queue_entry, later);
87 rcu_read_unlock();
88 (*pos)++;
89
90 return (&qe->later == &ima_measurements) ? NULL : qe;
91}
92
93static void ima_measurements_stop(struct seq_file *m, void *v)
94{
95}
96
97static void ima_putc(struct seq_file *m, void *data, int datalen)
98{
99 while (datalen--)
100 seq_putc(m, *(char *)data++);
101}
102
103/* print format:
104 * 32bit-le=pcr#
105 * char[20]=template digest
106 * 32bit-le=template name size
107 * char[n]=template name
108 * eventdata[n]=template specific data
109 */
110static int ima_measurements_show(struct seq_file *m, void *v)
111{
112 /* the list never shrinks, so we don't need a lock here */
113 struct ima_queue_entry *qe = v;
114 struct ima_template_entry *e;
115 int namelen;
116 u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
117
118 /* get entry */
119 e = qe->entry;
120 if (e == NULL)
121 return -1;
122
123 /*
124 * 1st: PCRIndex
125 * PCR used is always the same (config option) in
126 * little-endian format
127 */
128 ima_putc(m, &pcr, sizeof pcr);
129
130 /* 2nd: template digest */
131 ima_putc(m, e->digest, IMA_DIGEST_SIZE);
132
133 /* 3rd: template name size */
134 namelen = strlen(e->template_name);
135 ima_putc(m, &namelen, sizeof namelen);
136
137 /* 4th: template name */
138 ima_putc(m, e->template_name, namelen);
139
140 /* 5th: template specific data */
141 ima_template_show(m, (struct ima_template_data *)&e->template,
142 IMA_SHOW_BINARY);
143 return 0;
144}
145
146static struct seq_operations ima_measurments_seqops = {
147 .start = ima_measurements_start,
148 .next = ima_measurements_next,
149 .stop = ima_measurements_stop,
150 .show = ima_measurements_show
151};
152
153static int ima_measurements_open(struct inode *inode, struct file *file)
154{
155 return seq_open(file, &ima_measurments_seqops);
156}
157
158static struct file_operations ima_measurements_ops = {
159 .open = ima_measurements_open,
160 .read = seq_read,
161 .llseek = seq_lseek,
162 .release = seq_release,
163};
164
165static void ima_print_digest(struct seq_file *m, u8 *digest)
166{
167 int i;
168
169 for (i = 0; i < IMA_DIGEST_SIZE; i++)
170 seq_printf(m, "%02x", *(digest + i));
171}
172
173void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show)
174{
175 struct ima_template_data *entry = e;
176 int namelen;
177
178 switch (show) {
179 case IMA_SHOW_ASCII:
180 ima_print_digest(m, entry->digest);
181 seq_printf(m, " %s\n", entry->file_name);
182 break;
183 case IMA_SHOW_BINARY:
184 ima_putc(m, entry->digest, IMA_DIGEST_SIZE);
185
186 namelen = strlen(entry->file_name);
187 ima_putc(m, &namelen, sizeof namelen);
188 ima_putc(m, entry->file_name, namelen);
189 default:
190 break;
191 }
192}
193
194/* print in ascii */
195static int ima_ascii_measurements_show(struct seq_file *m, void *v)
196{
197 /* the list never shrinks, so we don't need a lock here */
198 struct ima_queue_entry *qe = v;
199 struct ima_template_entry *e;
200
201 /* get entry */
202 e = qe->entry;
203 if (e == NULL)
204 return -1;
205
206 /* 1st: PCR used (config option) */
207 seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
208
209 /* 2nd: SHA1 template hash */
210 ima_print_digest(m, e->digest);
211
212 /* 3th: template name */
213 seq_printf(m, " %s ", e->template_name);
214
215 /* 4th: template specific data */
216 ima_template_show(m, (struct ima_template_data *)&e->template,
217 IMA_SHOW_ASCII);
218 return 0;
219}
220
221static struct seq_operations ima_ascii_measurements_seqops = {
222 .start = ima_measurements_start,
223 .next = ima_measurements_next,
224 .stop = ima_measurements_stop,
225 .show = ima_ascii_measurements_show
226};
227
228static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
229{
230 return seq_open(file, &ima_ascii_measurements_seqops);
231}
232
233static struct file_operations ima_ascii_measurements_ops = {
234 .open = ima_ascii_measurements_open,
235 .read = seq_read,
236 .llseek = seq_lseek,
237 .release = seq_release,
238};
239
240static struct dentry *ima_dir;
241static struct dentry *binary_runtime_measurements;
242static struct dentry *ascii_runtime_measurements;
243static struct dentry *runtime_measurements_count;
244static struct dentry *violations;
245
246int ima_fs_init(void)
247{
248 ima_dir = securityfs_create_dir("ima", NULL);
249 if (IS_ERR(ima_dir))
250 return -1;
251
252 binary_runtime_measurements =
253 securityfs_create_file("binary_runtime_measurements",
254 S_IRUSR | S_IRGRP, ima_dir, NULL,
255 &ima_measurements_ops);
256 if (IS_ERR(binary_runtime_measurements))
257 goto out;
258
259 ascii_runtime_measurements =
260 securityfs_create_file("ascii_runtime_measurements",
261 S_IRUSR | S_IRGRP, ima_dir, NULL,
262 &ima_ascii_measurements_ops);
263 if (IS_ERR(ascii_runtime_measurements))
264 goto out;
265
266 runtime_measurements_count =
267 securityfs_create_file("runtime_measurements_count",
268 S_IRUSR | S_IRGRP, ima_dir, NULL,
269 &ima_measurements_count_ops);
270 if (IS_ERR(runtime_measurements_count))
271 goto out;
272
273 violations =
274 securityfs_create_file("violations", S_IRUSR | S_IRGRP,
275 ima_dir, NULL, &ima_htable_violations_ops);
276 if (IS_ERR(violations))
277 goto out;
278
279 return 0;
280
281out:
282 securityfs_remove(runtime_measurements_count);
283 securityfs_remove(ascii_runtime_measurements);
284 securityfs_remove(binary_runtime_measurements);
285 securityfs_remove(ima_dir);
286 return -1;
287}
288
289void __exit ima_fs_cleanup(void)
290{
291 securityfs_remove(violations);
292 securityfs_remove(runtime_measurements_count);
293 securityfs_remove(ascii_runtime_measurements);
294 securityfs_remove(binary_runtime_measurements);
295 securityfs_remove(ima_dir);
296}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index e0f02e328d77..cf227dbfac2c 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -86,5 +86,11 @@ int ima_init(void)
86 86
87 ima_add_boot_aggregate(); /* boot aggregate must be first entry */ 87 ima_add_boot_aggregate(); /* boot aggregate must be first entry */
88 ima_init_policy(); 88 ima_init_policy();
89 return 0; 89
90 return ima_fs_init();
91}
92
93void __exit ima_cleanup(void)
94{
95 ima_fs_cleanup();
90} 96}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 53cee4c512ce..871e356e8d6c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -274,6 +274,11 @@ static int __init init_ima(void)
274 return error; 274 return error;
275} 275}
276 276
277static void __exit cleanup_ima(void)
278{
279 ima_cleanup();
280}
281
277late_initcall(init_ima); /* Start IMA after the TPM is available */ 282late_initcall(init_ima); /* Start IMA after the TPM is available */
278 283
279MODULE_DESCRIPTION("Integrity Measurement Architecture"); 284MODULE_DESCRIPTION("Integrity Measurement Architecture");