blob: 5bcbaef5379816f967e07de8f9dd83af4090be5f [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",
Kylene Jo Hall7c69a472006-04-22 02:36:46 -0700123 "POST Contents",
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800124};
125
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800126/* returns pointer to start of pos. entry of tcg log */
127static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
128{
129 loff_t i;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800130 struct tpm_bios_log *log = m->private;
131 void *addr = log->bios_event_log;
132 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800133 struct tcpa_event *event;
134
135 /* read over *pos measurements */
136 for (i = 0; i < *pos; i++) {
137 event = addr;
138
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800139 if ((addr + sizeof(struct tcpa_event)) < limit) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800140 if (event->event_type == 0 && event->event_size == 0)
141 return NULL;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800142 addr += sizeof(struct tcpa_event) + event->event_size;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800143 }
144 }
145
146 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800147 if ((addr + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800148 return NULL;
149
150 event = addr;
151
152 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800153 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800154 return NULL;
155
156 return addr;
157}
158
159static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
160 loff_t *pos)
161{
162 struct tcpa_event *event = v;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800163 struct tpm_bios_log *log = m->private;
164 void *limit = log->bios_event_log_end;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800165
166 v += sizeof(struct tcpa_event) + event->event_size;
167
168 /* now check if current entry is valid */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800169 if ((v + sizeof(struct tcpa_event)) >= limit)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800170 return NULL;
171
172 event = v;
173
174 if (event->event_type == 0 && event->event_size == 0)
175 return NULL;
176
177 if ((event->event_type == 0 && event->event_size == 0) ||
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800178 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800179 return NULL;
180
181 (*pos)++;
182 return v;
183}
184
185static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
186{
187}
188
189static int get_event_name(char *dest, struct tcpa_event *event,
190 unsigned char * event_entry)
191{
192 const char *name = "";
193 char data[40] = "";
194 int i, n_len = 0, d_len = 0;
Kylene Jo Hall295b1172006-02-01 03:05:04 -0800195 u32 event_id;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800196
197 switch(event->event_type) {
198 case PREBOOT:
199 case POST_CODE:
200 case UNUSED:
201 case NO_ACTION:
202 case SCRTM_CONTENTS:
203 case SCRTM_VERSION:
204 case CPU_MICROCODE:
205 case PLATFORM_CONFIG_FLAGS:
206 case TABLE_OF_DEVICES:
207 case COMPACT_HASH:
208 case IPL:
209 case IPL_PARTITION_DATA:
210 case NONHOST_CODE:
211 case NONHOST_CONFIG:
212 case NONHOST_INFO:
213 name = tcpa_event_type_strings[event->event_type];
214 n_len = strlen(name);
215 break;
216 case SEPARATOR:
217 case ACTION:
218 if (MAX_TEXT_EVENT > event->event_size) {
219 name = event_entry;
220 n_len = event->event_size;
221 }
222 break;
223 case EVENT_TAG:
Andrew Morton1c40f7d2006-02-01 03:05:02 -0800224 event_id = be32_to_cpu(*((u32 *)event_entry));
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800225
226 /* ToDo Row data -> Base64 */
227
228 switch (event_id) {
229 case SMBIOS:
230 case BIS_CERT:
231 case CMOS:
232 case NVRAM:
233 case OPTION_ROM_EXEC:
234 case OPTION_ROM_CONFIG:
235 case OPTION_ROM_MICROCODE:
236 case S_CRTM_VERSION:
237 case S_CRTM_CONTENTS:
238 case POST_CONTENTS:
239 name = tcpa_pc_event_id_strings[event_id];
240 n_len = strlen(name);
241 break;
242 case POST_BIOS_ROM:
243 case ESCD:
244 name = tcpa_pc_event_id_strings[event_id];
245 n_len = strlen(name);
246 for (i = 0; i < 20; i++)
247 d_len += sprintf(data, "%02x",
248 event_entry[8 + i]);
249 break;
250 default:
251 break;
252 }
253 default:
254 break;
255 }
256
257 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
258 n_len, name, d_len, data);
259
260}
261
262static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
263{
264
265 char *eventname;
266 char data[4];
267 u32 help;
268 int i, len;
269 struct tcpa_event *event = (struct tcpa_event *) v;
270 unsigned char *event_entry =
271 (unsigned char *) (v + sizeof(struct tcpa_event));
272
273 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
274 if (!eventname) {
275 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
276 __func__);
277 return -ENOMEM;
278 }
279
280 /* 1st: PCR used is in little-endian format (4 bytes) */
281 help = le32_to_cpu(event->pcr_index);
282 memcpy(data, &help, 4);
283 for (i = 0; i < 4; i++)
284 seq_putc(m, data[i]);
285
286 /* 2nd: SHA1 (20 bytes) */
287 for (i = 0; i < 20; i++)
288 seq_putc(m, event->pcr_value[i]);
289
290 /* 3rd: event type identifier (4 bytes) */
291 help = le32_to_cpu(event->event_type);
292 memcpy(data, &help, 4);
293 for (i = 0; i < 4; i++)
294 seq_putc(m, data[i]);
295
296 len = 0;
297
298 len += get_event_name(eventname, event, event_entry);
299
300 /* 4th: filename <= 255 + \'0' delimiter */
301 if (len > TCG_EVENT_NAME_LEN_MAX)
302 len = TCG_EVENT_NAME_LEN_MAX;
303
304 for (i = 0; i < len; i++)
305 seq_putc(m, eventname[i]);
306
307 /* 5th: delimiter */
308 seq_putc(m, '\0');
309
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700310 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800311 return 0;
312}
313
314static int tpm_bios_measurements_release(struct inode *inode,
315 struct file *file)
316{
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800317 struct seq_file *seq = file->private_data;
318 struct tpm_bios_log *log = seq->private;
319
320 if (log) {
321 kfree(log->bios_event_log);
322 kfree(log);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800323 }
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800324
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800325 return seq_release(inode, file);
326}
327
328static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
329{
330 int len = 0;
331 int i;
332 char *eventname;
333 struct tcpa_event *event = v;
334 unsigned char *event_entry =
335 (unsigned char *) (v + sizeof(struct tcpa_event));
336
337 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
338 if (!eventname) {
339 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
340 __func__);
341 return -EFAULT;
342 }
343
344 seq_printf(m, "%2d ", event->pcr_index);
345
346 /* 2nd: SHA1 */
347 for (i = 0; i < 20; i++)
348 seq_printf(m, "%02x", event->pcr_value[i]);
349
350 /* 3rd: event type identifier */
351 seq_printf(m, " %02x", event->event_type);
352
353 len += get_event_name(eventname, event, event_entry);
354
355 /* 4th: eventname <= max + \'0' delimiter */
356 seq_printf(m, " %s\n", eventname);
357
Kylene Jo Hall59e89f32006-04-22 02:36:35 -0700358 kfree(eventname);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800359 return 0;
360}
361
362static struct seq_operations tpm_ascii_b_measurments_seqops = {
363 .start = tpm_bios_measurements_start,
364 .next = tpm_bios_measurements_next,
365 .stop = tpm_bios_measurements_stop,
366 .show = tpm_ascii_bios_measurements_show,
367};
368
369static struct seq_operations tpm_binary_b_measurments_seqops = {
370 .start = tpm_bios_measurements_start,
371 .next = tpm_bios_measurements_next,
372 .stop = tpm_bios_measurements_stop,
373 .show = tpm_binary_bios_measurements_show,
374};
375
376/* read binary bios log */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800377static int read_log(struct tpm_bios_log *log)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800378{
379 struct acpi_tcpa *buff;
380 acpi_status status;
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800381 struct acpi_table_header *virt;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800382
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800383 if (log->bios_event_log != NULL) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800384 printk(KERN_ERR
385 "%s: ERROR - Eventlog already initialized\n",
386 __func__);
387 return -EFAULT;
388 }
389
390 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
391 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
392 ACPI_LOGICAL_ADDRESSING,
393 (struct acpi_table_header **)
394 &buff);
395
396 if (ACPI_FAILURE(status)) {
397 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
398 __func__);
399 return -EIO;
400 }
401
402 if (buff->log_max_len == 0) {
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800403 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800404 return -EIO;
405 }
406
407 /* malloc EventLog space */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800408 log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
409 if (!log->bios_event_log) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800410 printk
411 ("%s: ERROR - Not enough Memory for BIOS measurements\n",
412 __func__);
413 return -ENOMEM;
414 }
415
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800416 log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800417
Kylene Jo Hall10296cb2006-02-01 03:05:04 -0800418 acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800419
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800420 memcpy(log->bios_event_log, virt, buff->log_max_len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800421
422 acpi_os_unmap_memory(virt, buff->log_max_len);
423 return 0;
424}
425
426static int tpm_ascii_bios_measurements_open(struct inode *inode,
427 struct file *file)
428{
429 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800430 struct tpm_bios_log *log;
431 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800432
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800433 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
434 if (!log)
435 return -ENOMEM;
436
437 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800438 return err;
439
440 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800441 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
442 if (!err) {
443 seq = file->private_data;
444 seq->private = log;
445 } else {
446 kfree(log->bios_event_log);
447 kfree(log);
448 }
449 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800450}
451
452struct file_operations tpm_ascii_bios_measurements_ops = {
453 .open = tpm_ascii_bios_measurements_open,
454 .read = seq_read,
455 .llseek = seq_lseek,
456 .release = tpm_bios_measurements_release,
457};
458
459static int tpm_binary_bios_measurements_open(struct inode *inode,
460 struct file *file)
461{
462 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800463 struct tpm_bios_log *log;
464 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800465
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800466 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
467 if (!log)
468 return -ENOMEM;
469
470 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800471 return err;
472
473 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800474 err = seq_open(file, &tpm_binary_b_measurments_seqops);
475 if (!err) {
476 seq = file->private_data;
477 seq->private = log;
478 } else {
479 kfree(log->bios_event_log);
480 kfree(log);
481 }
482 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800483}
484
485struct file_operations tpm_binary_bios_measurements_ops = {
486 .open = tpm_binary_bios_measurements_open,
487 .read = seq_read,
488 .llseek = seq_lseek,
489 .release = tpm_bios_measurements_release,
490};
491
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800492static int is_bad(void *p)
493{
494 if (!p)
495 return 1;
496 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
497 return 1;
498 return 0;
499}
500
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800501struct dentry **tpm_bios_log_setup(char *name)
502{
503 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
504
505 tpm_dir = securityfs_create_dir(name, NULL);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800506 if (is_bad(tpm_dir))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800507 goto out;
508
509 bin_file =
510 securityfs_create_file("binary_bios_measurements",
511 S_IRUSR | S_IRGRP, tpm_dir, NULL,
512 &tpm_binary_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800513 if (is_bad(bin_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800514 goto out_tpm;
515
516 ascii_file =
517 securityfs_create_file("ascii_bios_measurements",
518 S_IRUSR | S_IRGRP, tpm_dir, NULL,
519 &tpm_ascii_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800520 if (is_bad(ascii_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800521 goto out_bin;
522
523 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
524 if (!ret)
525 goto out_ascii;
526
527 ret[0] = ascii_file;
528 ret[1] = bin_file;
529 ret[2] = tpm_dir;
530
531 return ret;
532
533out_ascii:
534 securityfs_remove(ascii_file);
535out_bin:
536 securityfs_remove(bin_file);
537out_tpm:
538 securityfs_remove(tpm_dir);
539out:
540 return NULL;
541}
542EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
543
544void tpm_bios_log_teardown(struct dentry **lst)
545{
546 int i;
547
548 for (i = 0; i < 3; i++)
549 securityfs_remove(lst[i]);
550}
551EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
Kylene Jo Hall7bcee5b2006-02-01 03:05:03 -0800552MODULE_LICENSE("GPL");