blob: 537aa45d8c67a9cb98ca4fb44c7abdf85d625414 [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
309 return 0;
310}
311
312static int tpm_bios_measurements_release(struct inode *inode,
313 struct file *file)
314{
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800315 struct seq_file *seq = file->private_data;
316 struct tpm_bios_log *log = seq->private;
317
318 if (log) {
319 kfree(log->bios_event_log);
320 kfree(log);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800321 }
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800322
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800323 return seq_release(inode, file);
324}
325
326static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
327{
328 int len = 0;
329 int i;
330 char *eventname;
331 struct tcpa_event *event = v;
332 unsigned char *event_entry =
333 (unsigned char *) (v + sizeof(struct tcpa_event));
334
335 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
336 if (!eventname) {
337 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
338 __func__);
339 return -EFAULT;
340 }
341
342 seq_printf(m, "%2d ", event->pcr_index);
343
344 /* 2nd: SHA1 */
345 for (i = 0; i < 20; i++)
346 seq_printf(m, "%02x", event->pcr_value[i]);
347
348 /* 3rd: event type identifier */
349 seq_printf(m, " %02x", event->event_type);
350
351 len += get_event_name(eventname, event, event_entry);
352
353 /* 4th: eventname <= max + \'0' delimiter */
354 seq_printf(m, " %s\n", eventname);
355
356 return 0;
357}
358
359static struct seq_operations tpm_ascii_b_measurments_seqops = {
360 .start = tpm_bios_measurements_start,
361 .next = tpm_bios_measurements_next,
362 .stop = tpm_bios_measurements_stop,
363 .show = tpm_ascii_bios_measurements_show,
364};
365
366static struct seq_operations tpm_binary_b_measurments_seqops = {
367 .start = tpm_bios_measurements_start,
368 .next = tpm_bios_measurements_next,
369 .stop = tpm_bios_measurements_stop,
370 .show = tpm_binary_bios_measurements_show,
371};
372
373/* read binary bios log */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800374static int read_log(struct tpm_bios_log *log)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800375{
376 struct acpi_tcpa *buff;
377 acpi_status status;
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800378 struct acpi_table_header *virt;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800379
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800380 if (log->bios_event_log != NULL) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800381 printk(KERN_ERR
382 "%s: ERROR - Eventlog already initialized\n",
383 __func__);
384 return -EFAULT;
385 }
386
387 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
388 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
389 ACPI_LOGICAL_ADDRESSING,
390 (struct acpi_table_header **)
391 &buff);
392
393 if (ACPI_FAILURE(status)) {
394 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
395 __func__);
396 return -EIO;
397 }
398
399 if (buff->log_max_len == 0) {
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800400 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800401 return -EIO;
402 }
403
404 /* malloc EventLog space */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800405 log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
406 if (!log->bios_event_log) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800407 printk
408 ("%s: ERROR - Not enough Memory for BIOS measurements\n",
409 __func__);
410 return -ENOMEM;
411 }
412
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800413 log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800414
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800415 acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800416
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800417 memcpy(log->bios_event_log, virt, buff->log_max_len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800418
419 acpi_os_unmap_memory(virt, buff->log_max_len);
420 return 0;
421}
422
423static int tpm_ascii_bios_measurements_open(struct inode *inode,
424 struct file *file)
425{
426 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800427 struct tpm_bios_log *log;
428 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800429
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800430 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
431 if (!log)
432 return -ENOMEM;
433
434 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800435 return err;
436
437 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800438 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
439 if (!err) {
440 seq = file->private_data;
441 seq->private = log;
442 } else {
443 kfree(log->bios_event_log);
444 kfree(log);
445 }
446 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800447}
448
449struct file_operations tpm_ascii_bios_measurements_ops = {
450 .open = tpm_ascii_bios_measurements_open,
451 .read = seq_read,
452 .llseek = seq_lseek,
453 .release = tpm_bios_measurements_release,
454};
455
456static int tpm_binary_bios_measurements_open(struct inode *inode,
457 struct file *file)
458{
459 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800460 struct tpm_bios_log *log;
461 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800462
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800463 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
464 if (!log)
465 return -ENOMEM;
466
467 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800468 return err;
469
470 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800471 err = seq_open(file, &tpm_binary_b_measurments_seqops);
472 if (!err) {
473 seq = file->private_data;
474 seq->private = log;
475 } else {
476 kfree(log->bios_event_log);
477 kfree(log);
478 }
479 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800480}
481
482struct file_operations tpm_binary_bios_measurements_ops = {
483 .open = tpm_binary_bios_measurements_open,
484 .read = seq_read,
485 .llseek = seq_lseek,
486 .release = tpm_bios_measurements_release,
487};
488
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800489static int is_bad(void *p)
490{
491 if (!p)
492 return 1;
493 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
494 return 1;
495 return 0;
496}
497
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800498struct dentry **tpm_bios_log_setup(char *name)
499{
500 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
501
502 tpm_dir = securityfs_create_dir(name, NULL);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800503 if (is_bad(tpm_dir))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800504 goto out;
505
506 bin_file =
507 securityfs_create_file("binary_bios_measurements",
508 S_IRUSR | S_IRGRP, tpm_dir, NULL,
509 &tpm_binary_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800510 if (is_bad(bin_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800511 goto out_tpm;
512
513 ascii_file =
514 securityfs_create_file("ascii_bios_measurements",
515 S_IRUSR | S_IRGRP, tpm_dir, NULL,
516 &tpm_ascii_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800517 if (is_bad(ascii_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800518 goto out_bin;
519
520 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
521 if (!ret)
522 goto out_ascii;
523
524 ret[0] = ascii_file;
525 ret[1] = bin_file;
526 ret[2] = tpm_dir;
527
528 return ret;
529
530out_ascii:
531 securityfs_remove(ascii_file);
532out_bin:
533 securityfs_remove(bin_file);
534out_tpm:
535 securityfs_remove(tpm_dir);
536out:
537 return NULL;
538}
539EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
540
541void tpm_bios_log_teardown(struct dentry **lst)
542{
543 int i;
544
545 for (i = 0; i < 3; i++)
546 securityfs_remove(lst[i]);
547}
548EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
Kylene Jo Hall7bcee5b2006-02-01 03:05:03 -0800549MODULE_LICENSE("GPL");