WorkStruct: make allyesconfig
[deliverable/linux.git] / drivers / char / tpm / tpm_bios.c
1 /*
2 * Copyright (C) 2005 IBM Corporation
3 *
4 * Authors:
5 * Seiji Munetoh <munetoh@jp.ibm.com>
6 * Stefan Berger <stefanb@us.ibm.com>
7 * Reiner Sailer <sailer@watson.ibm.com>
8 * Kylene Hall <kjhall@us.ibm.com>
9 *
10 * Access to the eventlog extended by the TCG BIOS of PC platform
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 *
17 */
18
19 #include <linux/seq_file.h>
20 #include <linux/fs.h>
21 #include <linux/security.h>
22 #include <linux/module.h>
23 #include <acpi/acpi.h>
24 #include <acpi/actypes.h>
25 #include <acpi/actbl.h>
26 #include "tpm.h"
27
28 #define TCG_EVENT_NAME_LEN_MAX 255
29 #define MAX_TEXT_EVENT 1000 /* Max event string length */
30 #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
31
32 enum bios_platform_class {
33 BIOS_CLIENT = 0x00,
34 BIOS_SERVER = 0x01,
35 };
36
37 struct tpm_bios_log {
38 void *bios_event_log;
39 void *bios_event_log_end;
40 };
41
42 struct acpi_tcpa {
43 struct acpi_table_header hdr;
44 u16 platform_class;
45 union {
46 struct client_hdr {
47 u32 log_max_len __attribute__ ((packed));
48 u64 log_start_addr __attribute__ ((packed));
49 } client;
50 struct server_hdr {
51 u16 reserved;
52 u64 log_max_len __attribute__ ((packed));
53 u64 log_start_addr __attribute__ ((packed));
54 } server;
55 };
56 };
57
58 struct tcpa_event {
59 u32 pcr_index;
60 u32 event_type;
61 u8 pcr_value[20]; /* SHA1 */
62 u32 event_size;
63 u8 event_data[0];
64 };
65
66 enum tcpa_event_types {
67 PREBOOT = 0,
68 POST_CODE,
69 UNUSED,
70 NO_ACTION,
71 SEPARATOR,
72 ACTION,
73 EVENT_TAG,
74 SCRTM_CONTENTS,
75 SCRTM_VERSION,
76 CPU_MICROCODE,
77 PLATFORM_CONFIG_FLAGS,
78 TABLE_OF_DEVICES,
79 COMPACT_HASH,
80 IPL,
81 IPL_PARTITION_DATA,
82 NONHOST_CODE,
83 NONHOST_CONFIG,
84 NONHOST_INFO,
85 };
86
87 static const char* tcpa_event_type_strings[] = {
88 "PREBOOT",
89 "POST CODE",
90 "",
91 "NO ACTION",
92 "SEPARATOR",
93 "ACTION",
94 "EVENT TAG",
95 "S-CRTM Contents",
96 "S-CRTM Version",
97 "CPU Microcode",
98 "Platform Config Flags",
99 "Table of Devices",
100 "Compact Hash",
101 "IPL",
102 "IPL Partition Data",
103 "Non-Host Code",
104 "Non-Host Config",
105 "Non-Host Info"
106 };
107
108 struct tcpa_pc_event {
109 u32 event_id;
110 u32 event_size;
111 u8 event_data[0];
112 };
113
114 enum tcpa_pc_event_ids {
115 SMBIOS = 1,
116 BIS_CERT,
117 POST_BIOS_ROM,
118 ESCD,
119 CMOS,
120 NVRAM,
121 OPTION_ROM_EXEC,
122 OPTION_ROM_CONFIG,
123 OPTION_ROM_MICROCODE = 10,
124 S_CRTM_VERSION,
125 S_CRTM_CONTENTS,
126 POST_CONTENTS,
127 HOST_TABLE_OF_DEVICES,
128 };
129
130 static const char* tcpa_pc_event_id_strings[] = {
131 "",
132 "SMBIOS",
133 "BIS Certificate",
134 "POST BIOS ",
135 "ESCD ",
136 "CMOS",
137 "NVRAM",
138 "Option ROM",
139 "Option ROM config",
140 "",
141 "Option ROM microcode ",
142 "S-CRTM Version",
143 "S-CRTM Contents ",
144 "POST Contents ",
145 "Table of Devices",
146 };
147
148 /* returns pointer to start of pos. entry of tcg log */
149 static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
150 {
151 loff_t i;
152 struct tpm_bios_log *log = m->private;
153 void *addr = log->bios_event_log;
154 void *limit = log->bios_event_log_end;
155 struct tcpa_event *event;
156
157 /* read over *pos measurements */
158 for (i = 0; i < *pos; i++) {
159 event = addr;
160
161 if ((addr + sizeof(struct tcpa_event)) < limit) {
162 if (event->event_type == 0 && event->event_size == 0)
163 return NULL;
164 addr += sizeof(struct tcpa_event) + event->event_size;
165 }
166 }
167
168 /* now check if current entry is valid */
169 if ((addr + sizeof(struct tcpa_event)) >= limit)
170 return NULL;
171
172 event = addr;
173
174 if ((event->event_type == 0 && event->event_size == 0) ||
175 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
176 return NULL;
177
178 return addr;
179 }
180
181 static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
182 loff_t *pos)
183 {
184 struct tcpa_event *event = v;
185 struct tpm_bios_log *log = m->private;
186 void *limit = log->bios_event_log_end;
187
188 v += sizeof(struct tcpa_event) + event->event_size;
189
190 /* now check if current entry is valid */
191 if ((v + sizeof(struct tcpa_event)) >= limit)
192 return NULL;
193
194 event = v;
195
196 if (event->event_type == 0 && event->event_size == 0)
197 return NULL;
198
199 if ((event->event_type == 0 && event->event_size == 0) ||
200 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
201 return NULL;
202
203 (*pos)++;
204 return v;
205 }
206
207 static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
208 {
209 }
210
211 static int get_event_name(char *dest, struct tcpa_event *event,
212 unsigned char * event_entry)
213 {
214 const char *name = "";
215 char data[40] = "";
216 int i, n_len = 0, d_len = 0;
217 struct tcpa_pc_event *pc_event;
218
219 switch(event->event_type) {
220 case PREBOOT:
221 case POST_CODE:
222 case UNUSED:
223 case NO_ACTION:
224 case SCRTM_CONTENTS:
225 case SCRTM_VERSION:
226 case CPU_MICROCODE:
227 case PLATFORM_CONFIG_FLAGS:
228 case TABLE_OF_DEVICES:
229 case COMPACT_HASH:
230 case IPL:
231 case IPL_PARTITION_DATA:
232 case NONHOST_CODE:
233 case NONHOST_CONFIG:
234 case NONHOST_INFO:
235 name = tcpa_event_type_strings[event->event_type];
236 n_len = strlen(name);
237 break;
238 case SEPARATOR:
239 case ACTION:
240 if (MAX_TEXT_EVENT > event->event_size) {
241 name = event_entry;
242 n_len = event->event_size;
243 }
244 break;
245 case EVENT_TAG:
246 pc_event = (struct tcpa_pc_event *)event_entry;
247
248 /* ToDo Row data -> Base64 */
249
250 switch (pc_event->event_id) {
251 case SMBIOS:
252 case BIS_CERT:
253 case CMOS:
254 case NVRAM:
255 case OPTION_ROM_EXEC:
256 case OPTION_ROM_CONFIG:
257 case S_CRTM_VERSION:
258 name = tcpa_pc_event_id_strings[pc_event->event_id];
259 n_len = strlen(name);
260 break;
261 /* hash data */
262 case POST_BIOS_ROM:
263 case ESCD:
264 case OPTION_ROM_MICROCODE:
265 case S_CRTM_CONTENTS:
266 case POST_CONTENTS:
267 name = tcpa_pc_event_id_strings[pc_event->event_id];
268 n_len = strlen(name);
269 for (i = 0; i < 20; i++)
270 d_len += sprintf(&data[2*i], "%02x",
271 pc_event->event_data[i]);
272 break;
273 default:
274 break;
275 }
276 default:
277 break;
278 }
279
280 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
281 n_len, name, d_len, data);
282
283 }
284
285 static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
286 {
287 struct tcpa_event *event = v;
288 char *data = v;
289 int i;
290
291 for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
292 seq_putc(m, data[i]);
293
294 return 0;
295 }
296
297 static int tpm_bios_measurements_release(struct inode *inode,
298 struct file *file)
299 {
300 struct seq_file *seq = file->private_data;
301 struct tpm_bios_log *log = seq->private;
302
303 if (log) {
304 kfree(log->bios_event_log);
305 kfree(log);
306 }
307
308 return seq_release(inode, file);
309 }
310
311 static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
312 {
313 int len = 0;
314 int i;
315 char *eventname;
316 struct tcpa_event *event = v;
317 unsigned char *event_entry =
318 (unsigned char *) (v + sizeof(struct tcpa_event));
319
320 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
321 if (!eventname) {
322 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
323 __func__);
324 return -EFAULT;
325 }
326
327 seq_printf(m, "%2d ", event->pcr_index);
328
329 /* 2nd: SHA1 */
330 for (i = 0; i < 20; i++)
331 seq_printf(m, "%02x", event->pcr_value[i]);
332
333 /* 3rd: event type identifier */
334 seq_printf(m, " %02x", event->event_type);
335
336 len += get_event_name(eventname, event, event_entry);
337
338 /* 4th: eventname <= max + \'0' delimiter */
339 seq_printf(m, " %s\n", eventname);
340
341 kfree(eventname);
342 return 0;
343 }
344
345 static struct seq_operations tpm_ascii_b_measurments_seqops = {
346 .start = tpm_bios_measurements_start,
347 .next = tpm_bios_measurements_next,
348 .stop = tpm_bios_measurements_stop,
349 .show = tpm_ascii_bios_measurements_show,
350 };
351
352 static struct seq_operations tpm_binary_b_measurments_seqops = {
353 .start = tpm_bios_measurements_start,
354 .next = tpm_bios_measurements_next,
355 .stop = tpm_bios_measurements_stop,
356 .show = tpm_binary_bios_measurements_show,
357 };
358
359 /* read binary bios log */
360 static int read_log(struct tpm_bios_log *log)
361 {
362 struct acpi_tcpa *buff;
363 acpi_status status;
364 struct acpi_table_header *virt;
365 u64 len, start;
366
367 if (log->bios_event_log != NULL) {
368 printk(KERN_ERR
369 "%s: ERROR - Eventlog already initialized\n",
370 __func__);
371 return -EFAULT;
372 }
373
374 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
375 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
376 ACPI_LOGICAL_ADDRESSING,
377 (struct acpi_table_header **)
378 &buff);
379
380 if (ACPI_FAILURE(status)) {
381 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
382 __func__);
383 return -EIO;
384 }
385
386 switch(buff->platform_class) {
387 case BIOS_SERVER:
388 len = buff->server.log_max_len;
389 start = buff->server.log_start_addr;
390 break;
391 case BIOS_CLIENT:
392 default:
393 len = buff->client.log_max_len;
394 start = buff->client.log_start_addr;
395 break;
396 }
397 if (!len) {
398 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
399 return -EIO;
400 }
401
402 /* malloc EventLog space */
403 log->bios_event_log = kmalloc(len, GFP_KERNEL);
404 if (!log->bios_event_log) {
405 printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
406 __func__);
407 return -ENOMEM;
408 }
409
410 log->bios_event_log_end = log->bios_event_log + len;
411
412 acpi_os_map_memory(start, len, (void *) &virt);
413
414 memcpy(log->bios_event_log, virt, len);
415
416 acpi_os_unmap_memory(virt, len);
417 return 0;
418 }
419
420 static int tpm_ascii_bios_measurements_open(struct inode *inode,
421 struct file *file)
422 {
423 int err;
424 struct tpm_bios_log *log;
425 struct seq_file *seq;
426
427 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
428 if (!log)
429 return -ENOMEM;
430
431 if ((err = read_log(log)))
432 return err;
433
434 /* now register seq file */
435 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
436 if (!err) {
437 seq = file->private_data;
438 seq->private = log;
439 } else {
440 kfree(log->bios_event_log);
441 kfree(log);
442 }
443 return err;
444 }
445
446 struct file_operations tpm_ascii_bios_measurements_ops = {
447 .open = tpm_ascii_bios_measurements_open,
448 .read = seq_read,
449 .llseek = seq_lseek,
450 .release = tpm_bios_measurements_release,
451 };
452
453 static int tpm_binary_bios_measurements_open(struct inode *inode,
454 struct file *file)
455 {
456 int err;
457 struct tpm_bios_log *log;
458 struct seq_file *seq;
459
460 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
461 if (!log)
462 return -ENOMEM;
463
464 if ((err = read_log(log)))
465 return err;
466
467 /* now register seq file */
468 err = seq_open(file, &tpm_binary_b_measurments_seqops);
469 if (!err) {
470 seq = file->private_data;
471 seq->private = log;
472 } else {
473 kfree(log->bios_event_log);
474 kfree(log);
475 }
476 return err;
477 }
478
479 struct file_operations tpm_binary_bios_measurements_ops = {
480 .open = tpm_binary_bios_measurements_open,
481 .read = seq_read,
482 .llseek = seq_lseek,
483 .release = tpm_bios_measurements_release,
484 };
485
486 static int is_bad(void *p)
487 {
488 if (!p)
489 return 1;
490 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
491 return 1;
492 return 0;
493 }
494
495 struct dentry **tpm_bios_log_setup(char *name)
496 {
497 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
498
499 tpm_dir = securityfs_create_dir(name, NULL);
500 if (is_bad(tpm_dir))
501 goto out;
502
503 bin_file =
504 securityfs_create_file("binary_bios_measurements",
505 S_IRUSR | S_IRGRP, tpm_dir, NULL,
506 &tpm_binary_bios_measurements_ops);
507 if (is_bad(bin_file))
508 goto out_tpm;
509
510 ascii_file =
511 securityfs_create_file("ascii_bios_measurements",
512 S_IRUSR | S_IRGRP, tpm_dir, NULL,
513 &tpm_ascii_bios_measurements_ops);
514 if (is_bad(ascii_file))
515 goto out_bin;
516
517 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
518 if (!ret)
519 goto out_ascii;
520
521 ret[0] = ascii_file;
522 ret[1] = bin_file;
523 ret[2] = tpm_dir;
524
525 return ret;
526
527 out_ascii:
528 securityfs_remove(ascii_file);
529 out_bin:
530 securityfs_remove(bin_file);
531 out_tpm:
532 securityfs_remove(tpm_dir);
533 out:
534 return NULL;
535 }
536 EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
537
538 void tpm_bios_log_teardown(struct dentry **lst)
539 {
540 int i;
541
542 for (i = 0; i < 3; i++)
543 securityfs_remove(lst[i]);
544 }
545 EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
546 MODULE_LICENSE("GPL");
This page took 0.053534 seconds and 5 git commands to generate.