blob: 0549e2a35df85d710fc72e4ed984588c9f12235b [file] [log] [blame]
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -08001/*
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
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -080032struct tpm_bios_log {
33 void *bios_event_log;
34 void *bios_event_log_end;
35};
36
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -080037struct acpi_tcpa {
38 struct acpi_table_header hdr;
39 u16 reserved;
40 u32 log_max_len __attribute__ ((packed));
41 u32 log_start_addr __attribute__ ((packed));
42};
43
44struct tcpa_event {
45 u32 pcr_index;
46 u32 event_type;
47 u8 pcr_value[20]; /* SHA1 */
48 u32 event_size;
49 u8 event_data[0];
50};
51
52enum tcpa_event_types {
53 PREBOOT = 0,
54 POST_CODE,
55 UNUSED,
56 NO_ACTION,
57 SEPARATOR,
58 ACTION,
59 EVENT_TAG,
60 SCRTM_CONTENTS,
61 SCRTM_VERSION,
62 CPU_MICROCODE,
63 PLATFORM_CONFIG_FLAGS,
64 TABLE_OF_DEVICES,
65 COMPACT_HASH,
66 IPL,
67 IPL_PARTITION_DATA,
68 NONHOST_CODE,
69 NONHOST_CONFIG,
70 NONHOST_INFO,
71};
72
73static const char* tcpa_event_type_strings[] = {
74 "PREBOOT",
75 "POST CODE",
76 "",
77 "NO ACTION",
78 "SEPARATOR",
79 "ACTION",
80 "EVENT TAG",
81 "S-CRTM Contents",
82 "S-CRTM Version",
83 "CPU Microcode",
84 "Platform Config Flags",
85 "Table of Devices",
86 "Compact Hash",
87 "IPL",
88 "IPL Partition Data",
89 "Non-Host Code",
90 "Non-Host Config",
91 "Non-Host Info"
92};
93
94enum tcpa_pc_event_ids {
95 SMBIOS = 1,
96 BIS_CERT,
97 POST_BIOS_ROM,
98 ESCD,
99 CMOS,
100 NVRAM,
101 OPTION_ROM_EXEC,
102 OPTION_ROM_CONFIG,
103 OPTION_ROM_MICROCODE,
104 S_CRTM_VERSION,
105 S_CRTM_CONTENTS,
106 POST_CONTENTS,
107};
108
109static const char* tcpa_pc_event_id_strings[] = {
110 ""
111 "SMBIOS",
112 "BIS Certificate",
113 "POST BIOS ",
114 "ESCD ",
115 "CMOS",
116 "NVRAM",
117 "Option ROM",
118 "Option ROM config",
119 "Option ROM microcode",
120 "S-CRTM Version",
121 "S-CRTM Contents",
122 "S-CRTM POST Contents",
123};
124
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800125/* returns pointer to start of pos. entry of tcg log */
126static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
127{
128 loff_t i;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800129 struct tpm_bios_log *log = m->private;
130 void *addr = log->bios_event_log;
131 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800132 struct tcpa_event *event;
133
134 /* read over *pos measurements */
135 for (i = 0; i < *pos; i++) {
136 event = addr;
137
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800138 if ((addr + sizeof(struct tcpa_event)) < limit) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800139 if (event->event_type == 0 && event->event_size == 0)
140 return NULL;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800141 addr += sizeof(struct tcpa_event) + event->event_size;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800142 }
143 }
144
145 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800146 if ((addr + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800147 return NULL;
148
149 event = addr;
150
151 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800152 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800153 return NULL;
154
155 return addr;
156}
157
158static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
159 loff_t *pos)
160{
161 struct tcpa_event *event = v;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800162 struct tpm_bios_log *log = m->private;
163 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800164
165 v += sizeof(struct tcpa_event) + event->event_size;
166
167 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800168 if ((v + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800169 return NULL;
170
171 event = v;
172
173 if (event->event_type == 0 && event->event_size == 0)
174 return NULL;
175
176 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800177 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800178 return NULL;
179
180 (*pos)++;
181 return v;
182}
183
184static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
185{
186}
187
188static int get_event_name(char *dest, struct tcpa_event *event,
189 unsigned char * event_entry)
190{
191 const char *name = "";
192 char data[40] = "";
193 int i, n_len = 0, d_len = 0;
Kylene Jo Hall295b1172006-02-01 03:05:04 -0800194 u32 event_id;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800195
196 switch(event->event_type) {
197 case PREBOOT:
198 case POST_CODE:
199 case UNUSED:
200 case NO_ACTION:
201 case SCRTM_CONTENTS:
202 case SCRTM_VERSION:
203 case CPU_MICROCODE:
204 case PLATFORM_CONFIG_FLAGS:
205 case TABLE_OF_DEVICES:
206 case COMPACT_HASH:
207 case IPL:
208 case IPL_PARTITION_DATA:
209 case NONHOST_CODE:
210 case NONHOST_CONFIG:
211 case NONHOST_INFO:
212 name = tcpa_event_type_strings[event->event_type];
213 n_len = strlen(name);
214 break;
215 case SEPARATOR:
216 case ACTION:
217 if (MAX_TEXT_EVENT > event->event_size) {
218 name = event_entry;
219 n_len = event->event_size;
220 }
221 break;
222 case EVENT_TAG:
Andrew Morton1c40f7d2006-02-01 03:05:02 -0800223 event_id = be32_to_cpu(*((u32 *)event_entry));
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800224
225 /* ToDo Row data -> Base64 */
226
227 switch (event_id) {
228 case SMBIOS:
229 case BIS_CERT:
230 case CMOS:
231 case NVRAM:
232 case OPTION_ROM_EXEC:
233 case OPTION_ROM_CONFIG:
234 case OPTION_ROM_MICROCODE:
235 case S_CRTM_VERSION:
236 case S_CRTM_CONTENTS:
237 case POST_CONTENTS:
238 name = tcpa_pc_event_id_strings[event_id];
239 n_len = strlen(name);
240 break;
241 case POST_BIOS_ROM:
242 case ESCD:
243 name = tcpa_pc_event_id_strings[event_id];
244 n_len = strlen(name);
245 for (i = 0; i < 20; i++)
246 d_len += sprintf(data, "%02x",
247 event_entry[8 + i]);
248 break;
249 default:
250 break;
251 }
252 default:
253 break;
254 }
255
256 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
257 n_len, name, d_len, data);
258
259}
260
261static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
262{
263
264 char *eventname;
265 char data[4];
266 u32 help;
267 int i, len;
268 struct tcpa_event *event = (struct tcpa_event *) v;
269 unsigned char *event_entry =
270 (unsigned char *) (v + sizeof(struct tcpa_event));
271
272 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
273 if (!eventname) {
274 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
275 __func__);
276 return -ENOMEM;
277 }
278
279 /* 1st: PCR used is in little-endian format (4 bytes) */
280 help = le32_to_cpu(event->pcr_index);
281 memcpy(data, &help, 4);
282 for (i = 0; i < 4; i++)
283 seq_putc(m, data[i]);
284
285 /* 2nd: SHA1 (20 bytes) */
286 for (i = 0; i < 20; i++)
287 seq_putc(m, event->pcr_value[i]);
288
289 /* 3rd: event type identifier (4 bytes) */
290 help = le32_to_cpu(event->event_type);
291 memcpy(data, &help, 4);
292 for (i = 0; i < 4; i++)
293 seq_putc(m, data[i]);
294
295 len = 0;
296
297 len += get_event_name(eventname, event, event_entry);
298
299 /* 4th: filename <= 255 + \'0' delimiter */
300 if (len > TCG_EVENT_NAME_LEN_MAX)
301 len = TCG_EVENT_NAME_LEN_MAX;
302
303 for (i = 0; i < len; i++)
304 seq_putc(m, eventname[i]);
305
306 /* 5th: delimiter */
307 seq_putc(m, '\0');
308
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700309 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800310 return 0;
311}
312
313static int tpm_bios_measurements_release(struct inode *inode,
314 struct file *file)
315{
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800316 struct seq_file *seq = file->private_data;
317 struct tpm_bios_log *log = seq->private;
318
319 if (log) {
320 kfree(log->bios_event_log);
321 kfree(log);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800322 }
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800323
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800324 return seq_release(inode, file);
325}
326
327static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
328{
329 int len = 0;
330 int i;
331 char *eventname;
332 struct tcpa_event *event = v;
333 unsigned char *event_entry =
334 (unsigned char *) (v + sizeof(struct tcpa_event));
335
336 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
337 if (!eventname) {
338 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
339 __func__);
340 return -EFAULT;
341 }
342
343 seq_printf(m, "%2d ", event->pcr_index);
344
345 /* 2nd: SHA1 */
346 for (i = 0; i < 20; i++)
347 seq_printf(m, "%02x", event->pcr_value[i]);
348
349 /* 3rd: event type identifier */
350 seq_printf(m, " %02x", event->event_type);
351
352 len += get_event_name(eventname, event, event_entry);
353
354 /* 4th: eventname <= max + \'0' delimiter */
355 seq_printf(m, " %s\n", eventname);
356
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700357 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800358 return 0;
359}
360
361static struct seq_operations tpm_ascii_b_measurments_seqops = {
362 .start = tpm_bios_measurements_start,
363 .next = tpm_bios_measurements_next,
364 .stop = tpm_bios_measurements_stop,
365 .show = tpm_ascii_bios_measurements_show,
366};
367
368static struct seq_operations tpm_binary_b_measurments_seqops = {
369 .start = tpm_bios_measurements_start,
370 .next = tpm_bios_measurements_next,
371 .stop = tpm_bios_measurements_stop,
372 .show = tpm_binary_bios_measurements_show,
373};
374
375/* read binary bios log */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800376static int read_log(struct tpm_bios_log *log)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800377{
378 struct acpi_tcpa *buff;
379 acpi_status status;
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800380 struct acpi_table_header *virt;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800381
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800382 if (log->bios_event_log != NULL) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800383 printk(KERN_ERR
384 "%s: ERROR - Eventlog already initialized\n",
385 __func__);
386 return -EFAULT;
387 }
388
389 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
390 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
391 ACPI_LOGICAL_ADDRESSING,
392 (struct acpi_table_header **)
393 &buff);
394
395 if (ACPI_FAILURE(status)) {
396 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
397 __func__);
398 return -EIO;
399 }
400
401 if (buff->log_max_len == 0) {
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800402 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800403 return -EIO;
404 }
405
406 /* malloc EventLog space */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800407 log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
408 if (!log->bios_event_log) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800409 printk
410 ("%s: ERROR - Not enough Memory for BIOS measurements\n",
411 __func__);
412 return -ENOMEM;
413 }
414
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800415 log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800416
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800417 acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800418
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800419 memcpy(log->bios_event_log, virt, buff->log_max_len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800420
421 acpi_os_unmap_memory(virt, buff->log_max_len);
422 return 0;
423}
424
425static int tpm_ascii_bios_measurements_open(struct inode *inode,
426 struct file *file)
427{
428 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800429 struct tpm_bios_log *log;
430 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800431
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800432 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
433 if (!log)
434 return -ENOMEM;
435
436 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800437 return err;
438
439 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800440 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
441 if (!err) {
442 seq = file->private_data;
443 seq->private = log;
444 } else {
445 kfree(log->bios_event_log);
446 kfree(log);
447 }
448 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800449}
450
451struct file_operations tpm_ascii_bios_measurements_ops = {
452 .open = tpm_ascii_bios_measurements_open,
453 .read = seq_read,
454 .llseek = seq_lseek,
455 .release = tpm_bios_measurements_release,
456};
457
458static int tpm_binary_bios_measurements_open(struct inode *inode,
459 struct file *file)
460{
461 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800462 struct tpm_bios_log *log;
463 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800464
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800465 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
466 if (!log)
467 return -ENOMEM;
468
469 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800470 return err;
471
472 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800473 err = seq_open(file, &tpm_binary_b_measurments_seqops);
474 if (!err) {
475 seq = file->private_data;
476 seq->private = log;
477 } else {
478 kfree(log->bios_event_log);
479 kfree(log);
480 }
481 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800482}
483
484struct file_operations tpm_binary_bios_measurements_ops = {
485 .open = tpm_binary_bios_measurements_open,
486 .read = seq_read,
487 .llseek = seq_lseek,
488 .release = tpm_bios_measurements_release,
489};
490
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800491static int is_bad(void *p)
492{
493 if (!p)
494 return 1;
495 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
496 return 1;
497 return 0;
498}
499
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800500struct dentry **tpm_bios_log_setup(char *name)
501{
502 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
503
504 tpm_dir = securityfs_create_dir(name, NULL);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800505 if (is_bad(tpm_dir))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800506 goto out;
507
508 bin_file =
509 securityfs_create_file("binary_bios_measurements",
510 S_IRUSR | S_IRGRP, tpm_dir, NULL,
511 &tpm_binary_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800512 if (is_bad(bin_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800513 goto out_tpm;
514
515 ascii_file =
516 securityfs_create_file("ascii_bios_measurements",
517 S_IRUSR | S_IRGRP, tpm_dir, NULL,
518 &tpm_ascii_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800519 if (is_bad(ascii_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800520 goto out_bin;
521
522 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
523 if (!ret)
524 goto out_ascii;
525
526 ret[0] = ascii_file;
527 ret[1] = bin_file;
528 ret[2] = tpm_dir;
529
530 return ret;
531
532out_ascii:
533 securityfs_remove(ascii_file);
534out_bin:
535 securityfs_remove(bin_file);
536out_tpm:
537 securityfs_remove(tpm_dir);
538out:
539 return NULL;
540}
541EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
542
543void tpm_bios_log_teardown(struct dentry **lst)
544{
545 int i;
546
547 for (i = 0; i < 3; i++)
548 securityfs_remove(lst[i]);
549}
550EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
Kylene Jo Hall7bcee5b2006-02-01 03:05:03 -0800551MODULE_LICENSE("GPL");