blob: 9ffa5643e79dd90e6c05178e093668f3e908c9af [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;
194 u32 event_id, event_data_size;
195
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:
223 event_id = be32_to_cpu(event_entry);
224 event_data_size = be32_to_cpu(&event_entry[4]);
225
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
310 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
357 return 0;
358}
359
360static struct seq_operations tpm_ascii_b_measurments_seqops = {
361 .start = tpm_bios_measurements_start,
362 .next = tpm_bios_measurements_next,
363 .stop = tpm_bios_measurements_stop,
364 .show = tpm_ascii_bios_measurements_show,
365};
366
367static struct seq_operations tpm_binary_b_measurments_seqops = {
368 .start = tpm_bios_measurements_start,
369 .next = tpm_bios_measurements_next,
370 .stop = tpm_bios_measurements_stop,
371 .show = tpm_binary_bios_measurements_show,
372};
373
374/* read binary bios log */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800375static int read_log(struct tpm_bios_log *log)
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800376{
377 struct acpi_tcpa *buff;
378 acpi_status status;
379 void *virt;
380
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800381 if (log->bios_event_log != NULL) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800382 printk(KERN_ERR
383 "%s: ERROR - Eventlog already initialized\n",
384 __func__);
385 return -EFAULT;
386 }
387
388 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
389 status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
390 ACPI_LOGICAL_ADDRESSING,
391 (struct acpi_table_header **)
392 &buff);
393
394 if (ACPI_FAILURE(status)) {
395 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
396 __func__);
397 return -EIO;
398 }
399
400 if (buff->log_max_len == 0) {
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800401 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800402 return -EIO;
403 }
404
405 /* malloc EventLog space */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800406 log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
407 if (!log->bios_event_log) {
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800408 printk
409 ("%s: ERROR - Not enough Memory for BIOS measurements\n",
410 __func__);
411 return -ENOMEM;
412 }
413
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800414 log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800415
416 acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt);
417
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800418 memcpy(log->bios_event_log, virt, buff->log_max_len);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800419
420 acpi_os_unmap_memory(virt, buff->log_max_len);
421 return 0;
422}
423
424static int tpm_ascii_bios_measurements_open(struct inode *inode,
425 struct file *file)
426{
427 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800428 struct tpm_bios_log *log;
429 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800430
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800431 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
432 if (!log)
433 return -ENOMEM;
434
435 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800436 return err;
437
438 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800439 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
440 if (!err) {
441 seq = file->private_data;
442 seq->private = log;
443 } else {
444 kfree(log->bios_event_log);
445 kfree(log);
446 }
447 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800448}
449
450struct file_operations tpm_ascii_bios_measurements_ops = {
451 .open = tpm_ascii_bios_measurements_open,
452 .read = seq_read,
453 .llseek = seq_lseek,
454 .release = tpm_bios_measurements_release,
455};
456
457static int tpm_binary_bios_measurements_open(struct inode *inode,
458 struct file *file)
459{
460 int err;
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800461 struct tpm_bios_log *log;
462 struct seq_file *seq;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800463
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800464 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
465 if (!log)
466 return -ENOMEM;
467
468 if ((err = read_log(log)))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800469 return err;
470
471 /* now register seq file */
Kylene Jo Halld09cf7d2006-01-08 01:03:48 -0800472 err = seq_open(file, &tpm_binary_b_measurments_seqops);
473 if (!err) {
474 seq = file->private_data;
475 seq->private = log;
476 } else {
477 kfree(log->bios_event_log);
478 kfree(log);
479 }
480 return err;
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800481}
482
483struct file_operations tpm_binary_bios_measurements_ops = {
484 .open = tpm_binary_bios_measurements_open,
485 .read = seq_read,
486 .llseek = seq_lseek,
487 .release = tpm_bios_measurements_release,
488};
489
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800490static int is_bad(void *p)
491{
492 if (!p)
493 return 1;
494 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
495 return 1;
496 return 0;
497}
498
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800499struct dentry **tpm_bios_log_setup(char *name)
500{
501 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
502
503 tpm_dir = securityfs_create_dir(name, NULL);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800504 if (is_bad(tpm_dir))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800505 goto out;
506
507 bin_file =
508 securityfs_create_file("binary_bios_measurements",
509 S_IRUSR | S_IRGRP, tpm_dir, NULL,
510 &tpm_binary_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800511 if (is_bad(bin_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800512 goto out_tpm;
513
514 ascii_file =
515 securityfs_create_file("ascii_bios_measurements",
516 S_IRUSR | S_IRGRP, tpm_dir, NULL,
517 &tpm_ascii_bios_measurements_ops);
Andrew Mortonca4a031f2006-02-01 03:05:01 -0800518 if (is_bad(ascii_file))
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800519 goto out_bin;
520
521 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
522 if (!ret)
523 goto out_ascii;
524
525 ret[0] = ascii_file;
526 ret[1] = bin_file;
527 ret[2] = tpm_dir;
528
529 return ret;
530
531out_ascii:
532 securityfs_remove(ascii_file);
533out_bin:
534 securityfs_remove(bin_file);
535out_tpm:
536 securityfs_remove(tpm_dir);
537out:
538 return NULL;
539}
540EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
541
542void tpm_bios_log_teardown(struct dentry **lst)
543{
544 int i;
545
546 for (i = 0; i < 3; i++)
547 securityfs_remove(lst[i]);
548}
549EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);