xref: /linux/security/integrity/ima/ima_fs.c (revision bab739378758a1e2b2d7ddcee7bc06cf4c591c3c)
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
26 static 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 
36 static 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 
43 static struct file_operations ima_htable_violations_ops = {
44 	.read = ima_show_htable_violations
45 };
46 
47 static 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 
55 static struct file_operations ima_measurements_count_ops = {
56 	.read = ima_show_measurements_count
57 };
58 
59 /* returns pointer to hlist_node */
60 static 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 
77 static 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 
93 static void ima_measurements_stop(struct seq_file *m, void *v)
94 {
95 }
96 
97 static 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  */
110 static 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 
146 static 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 
153 static int ima_measurements_open(struct inode *inode, struct file *file)
154 {
155 	return seq_open(file, &ima_measurments_seqops);
156 }
157 
158 static 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 
165 static 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 
173 void 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 */
195 static 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 
221 static 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 
228 static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
229 {
230 	return seq_open(file, &ima_ascii_measurements_seqops);
231 }
232 
233 static 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 
240 static struct dentry *ima_dir;
241 static struct dentry *binary_runtime_measurements;
242 static struct dentry *ascii_runtime_measurements;
243 static struct dentry *runtime_measurements_count;
244 static struct dentry *violations;
245 
246 int 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 
281 out:
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 
289 void __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 }
297