blob: e45f0d3d12de5427cf708585d08e3c615d8e087e [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 Hall8b006db2006-04-22 02:39:07 -070032enum bios_platform_class {
33 BIOS_CLIENT = 0x00,
34 BIOS_SERVER = 0x01,
35};
36
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -080037struct tpm_bios_log {
38 void *bios_event_log;
39 void *bios_event_log_end;
40};
41
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -080042struct acpi_tcpa {
43 struct acpi_table_header hdr;
Kylene Jo Hall8b006db2006-04-22 02:39:07 -070044 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 };
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -080056};
57
58struct 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
66enum 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
87static 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
108enum tcpa_pc_event_ids {
109 SMBIOS = 1,
110 BIS_CERT,
111 POST_BIOS_ROM,
112 ESCD,
113 CMOS,
114 NVRAM,
115 OPTION_ROM_EXEC,
116 OPTION_ROM_CONFIG,
117 OPTION_ROM_MICROCODE,
118 S_CRTM_VERSION,
119 S_CRTM_CONTENTS,
120 POST_CONTENTS,
121};
122
123static const char* tcpa_pc_event_id_strings[] = {
124 ""
125 "SMBIOS",
126 "BIS Certificate",
127 "POST BIOS ",
128 "ESCD ",
129 "CMOS",
130 "NVRAM",
131 "Option ROM",
132 "Option ROM config",
133 "Option ROM microcode",
134 "S-CRTM Version",
135 "S-CRTM Contents",
136 "S-CRTM POST Contents",
Kylene Jo Hall7c69a472006-04-22 02:36:46 -0700137 "POST Contents",
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800138};
139
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800140/* returns pointer to start of pos. entry of tcg log */
141static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
142{
143 loff_t i;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800144 struct tpm_bios_log *log = m->private;
145 void *addr = log->bios_event_log;
146 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800147 struct tcpa_event *event;
148
149 /* read over *pos measurements */
150 for (i = 0; i < *pos; i++) {
151 event = addr;
152
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800153 if ((addr + sizeof(struct tcpa_event)) < limit) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800154 if (event->event_type == 0 && event->event_size == 0)
155 return NULL;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800156 addr += sizeof(struct tcpa_event) + event->event_size;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800157 }
158 }
159
160 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800161 if ((addr + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800162 return NULL;
163
164 event = addr;
165
166 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800167 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800168 return NULL;
169
170 return addr;
171}
172
173static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
174 loff_t *pos)
175{
176 struct tcpa_event *event = v;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800177 struct tpm_bios_log *log = m->private;
178 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800179
180 v += sizeof(struct tcpa_event) + event->event_size;
181
182 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800183 if ((v + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800184 return NULL;
185
186 event = v;
187
188 if (event->event_type == 0 && event->event_size == 0)
189 return NULL;
190
191 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800192 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800193 return NULL;
194
195 (*pos)++;
196 return v;
197}
198
199static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
200{
201}
202
203static int get_event_name(char *dest, struct tcpa_event *event,
204 unsigned char * event_entry)
205{
206 const char *name = "";
207 char data[40] = "";
208 int i, n_len = 0, d_len = 0;
Kylene Jo Hall295b1172006-02-01 03:05:04 -0800209 u32 event_id;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800210
211 switch(event->event_type) {
212 case PREBOOT:
213 case POST_CODE:
214 case UNUSED:
215 case NO_ACTION:
216 case SCRTM_CONTENTS:
217 case SCRTM_VERSION:
218 case CPU_MICROCODE:
219 case PLATFORM_CONFIG_FLAGS:
220 case TABLE_OF_DEVICES:
221 case COMPACT_HASH:
222 case IPL:
223 case IPL_PARTITION_DATA:
224 case NONHOST_CODE:
225 case NONHOST_CONFIG:
226 case NONHOST_INFO:
227 name = tcpa_event_type_strings[event->event_type];
228 n_len = strlen(name);
229 break;
230 case SEPARATOR:
231 case ACTION:
232 if (MAX_TEXT_EVENT > event->event_size) {
233 name = event_entry;
234 n_len = event->event_size;
235 }
236 break;
237 case EVENT_TAG:
Andrew Morton1c40f7d2006-02-01 03:05:02 -0800238 event_id = be32_to_cpu(*((u32 *)event_entry));
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800239
240 /* ToDo Row data -> Base64 */
241
242 switch (event_id) {
243 case SMBIOS:
244 case BIS_CERT:
245 case CMOS:
246 case NVRAM:
247 case OPTION_ROM_EXEC:
248 case OPTION_ROM_CONFIG:
249 case OPTION_ROM_MICROCODE:
250 case S_CRTM_VERSION:
251 case S_CRTM_CONTENTS:
252 case POST_CONTENTS:
253 name = tcpa_pc_event_id_strings[event_id];
254 n_len = strlen(name);
255 break;
256 case POST_BIOS_ROM:
257 case ESCD:
258 name = tcpa_pc_event_id_strings[event_id];
259 n_len = strlen(name);
260 for (i = 0; i < 20; i++)
261 d_len += sprintf(data, "%02x",
262 event_entry[8 + i]);
263 break;
264 default:
265 break;
266 }
267 default:
268 break;
269 }
270
271 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
272 n_len, name, d_len, data);
273
274}
275
276static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
277{
278
279 char *eventname;
280 char data[4];
281 u32 help;
282 int i, len;
283 struct tcpa_event *event = (struct tcpa_event *) v;
284 unsigned char *event_entry =
285 (unsigned char *) (v + sizeof(struct tcpa_event));
286
287 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
288 if (!eventname) {
289 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
290 __func__);
291 return -ENOMEM;
292 }
293
294 /* 1st: PCR used is in little-endian format (4 bytes) */
295 help = le32_to_cpu(event->pcr_index);
296 memcpy(data, &help, 4);
297 for (i = 0; i < 4; i++)
298 seq_putc(m, data[i]);
299
300 /* 2nd: SHA1 (20 bytes) */
301 for (i = 0; i < 20; i++)
302 seq_putc(m, event->pcr_value[i]);
303
304 /* 3rd: event type identifier (4 bytes) */
305 help = le32_to_cpu(event->event_type);
306 memcpy(data, &help, 4);
307 for (i = 0; i < 4; i++)
308 seq_putc(m, data[i]);
309
310 len = 0;
311
312 len += get_event_name(eventname, event, event_entry);
313
314 /* 4th: filename <= 255 + \'0' delimiter */
315 if (len > TCG_EVENT_NAME_LEN_MAX)
316 len = TCG_EVENT_NAME_LEN_MAX;
317
318 for (i = 0; i < len; i++)
319 seq_putc(m, eventname[i]);
320
321 /* 5th: delimiter */
322 seq_putc(m, '\0');
323
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700324 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800325 return 0;
326}
327
328static int tpm_bios_measurements_release(struct inode *inode,
329 struct file *file)
330{
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800331 struct seq_file *seq = file->private_data;
332 struct tpm_bios_log *log = seq->private;
333
334 if (log) {
335 kfree(log->bios_event_log);
336 kfree(log);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800337 }
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800338
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800339 return seq_release(inode, file);
340}
341
342static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
343{
344 int len = 0;
345 int i;
346 char *eventname;
347 struct tcpa_event *event = v;
348 unsigned char *event_entry =
349 (unsigned char *) (v + sizeof(struct tcpa_event));
350
351 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
352 if (!eventname) {
353 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
354 __func__);
355 return -EFAULT;
356 }
357
358 seq_printf(m, "%2d ", event->pcr_index);
359
360 /* 2nd: SHA1 */
361 for (i = 0; i < 20; i++)
362 seq_printf(m, "%02x", event->pcr_value[i]);
363
364 /* 3rd: event type identifier */
365 seq_printf(m, " %02x", event->event_type);
366
367 len += get_event_name(eventname, event, event_entry);
368
369 /* 4th: eventname <= max + \'0' delimiter */
370 seq_printf(m, " %s\n", eventname);
371
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700372 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800373 return 0;
374}
375
376static struct seq_operations tpm_ascii_b_measurments_seqops = {
377 .start = tpm_bios_measurements_start,
378 .next = tpm_bios_measurements_next,
379 .stop = tpm_bios_measurements_stop,
380 .show = tpm_ascii_bios_measurements_show,
381};
382
383static struct seq_operations tpm_binary_b_measurments_seqops = {
384 .start = tpm_bios_measurements_start,
385 .next = tpm_bios_measurements_next,
386 .stop = tpm_bios_measurements_stop,
387 .show = tpm_binary_bios_measurements_show,
388};
389
390/* read binary bios log */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800391static int read_log(struct tpm_bios_log *log)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800392{
393 struct acpi_tcpa *buff;
394 acpi_status status;
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800395 struct acpi_table_header *virt;
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700396 u64 len, start;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800397
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800398 if (log->bios_event_log != NULL) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800399 printk(KERN_ERR
400 "%s: ERROR - Eventlog already initialized\n",
401 __func__);
402 return -EFAULT;
403 }
404
405 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
406 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
407 ACPI_LOGICAL_ADDRESSING,
408 (struct acpi_table_header **)
409 &buff);
410
411 if (ACPI_FAILURE(status)) {
412 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
413 __func__);
414 return -EIO;
415 }
416
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700417 switch(buff->platform_class) {
418 case BIOS_SERVER:
419 len = buff->server.log_max_len;
420 start = buff->server.log_start_addr;
421 break;
422 case BIOS_CLIENT:
423 default:
424 len = buff->client.log_max_len;
425 start = buff->client.log_start_addr;
426 break;
427 }
428 if (!len) {
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800429 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800430 return -EIO;
431 }
432
433 /* malloc EventLog space */
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700434 log->bios_event_log = kmalloc(len, GFP_KERNEL);
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800435 if (!log->bios_event_log) {
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700436 printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
437 __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800438 return -ENOMEM;
439 }
440
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700441 log->bios_event_log_end = log->bios_event_log + len;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800442
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700443 acpi_os_map_memory(start, len, (void *) &virt);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800444
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700445 memcpy(log->bios_event_log, virt, len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800446
Kylene Jo Hall8b006db2006-04-22 02:39:07 -0700447 acpi_os_unmap_memory(virt, len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800448 return 0;
449}
450
451static int tpm_ascii_bios_measurements_open(struct inode *inode,
452 struct file *file)
453{
454 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800455 struct tpm_bios_log *log;
456 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800457
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800458 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
459 if (!log)
460 return -ENOMEM;
461
462 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800463 return err;
464
465 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800466 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
467 if (!err) {
468 seq = file->private_data;
469 seq->private = log;
470 } else {
471 kfree(log->bios_event_log);
472 kfree(log);
473 }
474 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800475}
476
477struct file_operations tpm_ascii_bios_measurements_ops = {
478 .open = tpm_ascii_bios_measurements_open,
479 .read = seq_read,
480 .llseek = seq_lseek,
481 .release = tpm_bios_measurements_release,
482};
483
484static int tpm_binary_bios_measurements_open(struct inode *inode,
485 struct file *file)
486{
487 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800488 struct tpm_bios_log *log;
489 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800490
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800491 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
492 if (!log)
493 return -ENOMEM;
494
495 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800496 return err;
497
498 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800499 err = seq_open(file, &tpm_binary_b_measurments_seqops);
500 if (!err) {
501 seq = file->private_data;
502 seq->private = log;
503 } else {
504 kfree(log->bios_event_log);
505 kfree(log);
506 }
507 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800508}
509
510struct file_operations tpm_binary_bios_measurements_ops = {
511 .open = tpm_binary_bios_measurements_open,
512 .read = seq_read,
513 .llseek = seq_lseek,
514 .release = tpm_bios_measurements_release,
515};
516
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800517static int is_bad(void *p)
518{
519 if (!p)
520 return 1;
521 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
522 return 1;
523 return 0;
524}
525
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800526struct dentry **tpm_bios_log_setup(char *name)
527{
528 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
529
530 tpm_dir = securityfs_create_dir(name, NULL);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800531 if (is_bad(tpm_dir))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800532 goto out;
533
534 bin_file =
535 securityfs_create_file("binary_bios_measurements",
536 S_IRUSR | S_IRGRP, tpm_dir, NULL,
537 &tpm_binary_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800538 if (is_bad(bin_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800539 goto out_tpm;
540
541 ascii_file =
542 securityfs_create_file("ascii_bios_measurements",
543 S_IRUSR | S_IRGRP, tpm_dir, NULL,
544 &tpm_ascii_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800545 if (is_bad(ascii_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800546 goto out_bin;
547
548 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
549 if (!ret)
550 goto out_ascii;
551
552 ret[0] = ascii_file;
553 ret[1] = bin_file;
554 ret[2] = tpm_dir;
555
556 return ret;
557
558out_ascii:
559 securityfs_remove(ascii_file);
560out_bin:
561 securityfs_remove(bin_file);
562out_tpm:
563 securityfs_remove(tpm_dir);
564out:
565 return NULL;
566}
567EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
568
569void tpm_bios_log_teardown(struct dentry **lst)
570{
571 int i;
572
573 for (i = 0; i < 3; i++)
574 securityfs_remove(lst[i]);
575}
576EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
Kylene Jo Hall7bcee5b2006-02-01 03:05:03 -0800577MODULE_LICENSE("GPL");