aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_fs.c
diff options
context:
space:
mode:
authorMimi Zohar <zohar@linux.vnet.ibm.com>2009-02-04 09:06:59 -0500
committerJames Morris <jmorris@namei.org>2009-02-05 17:05:31 -0500
commitbab739378758a1e2b2d7ddcee7bc06cf4c591c3c (patch)
tree5465ab3ccaf20ab8fb4f649aad8d1b08bfe49232 /security/integrity/ima/ima_fs.c
parent3323eec921efd815178a23107ab63588c605c0b2 (diff)
integrity: IMA display
Make the measurement lists available through securityfs. - removed test for NULL return code from securityfs_create_file/dir Signed-off-by: Mimi Zohar <zohar@us.ibm.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/integrity/ima/ima_fs.c')
-rw-r--r--security/integrity/ima/ima_fs.c296
1 files changed, 296 insertions, 0 deletions
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}