Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-block.git] / drivers / char / tpm / tpm_bios.c
CommitLineData
55a82ab3
KJH
1/*
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 *
8e81cc13
KY
10 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
11 *
55a82ab3
KJH
12 * Access to the eventlog extended by the TCG BIOS of PC platform
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version
17 * 2 of the License, or (at your option) any later version.
18 *
19 */
20
21#include <linux/seq_file.h>
22#include <linux/fs.h>
23#include <linux/security.h>
24#include <linux/module.h>
25#include <acpi/acpi.h>
55a82ab3
KJH
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
8b006db6
KJH
32enum bios_platform_class {
33 BIOS_CLIENT = 0x00,
34 BIOS_SERVER = 0x01,
35};
36
d09cf7d7
KJH
37struct tpm_bios_log {
38 void *bios_event_log;
39 void *bios_event_log_end;
40};
41
55a82ab3
KJH
42struct acpi_tcpa {
43 struct acpi_table_header hdr;
8b006db6
KJH
44 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 };
55a82ab3
KJH
56};
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
de66a695
SM
108struct tcpa_pc_event {
109 u32 event_id;
110 u32 event_size;
111 u8 event_data[0];
112};
113
55a82ab3
KJH
114enum tcpa_pc_event_ids {
115 SMBIOS = 1,
116 BIS_CERT,
117 POST_BIOS_ROM,
118 ESCD,
119 CMOS,
120 NVRAM,
121 OPTION_ROM_EXEC,
122 OPTION_ROM_CONFIG,
de66a695 123 OPTION_ROM_MICROCODE = 10,
55a82ab3
KJH
124 S_CRTM_VERSION,
125 S_CRTM_CONTENTS,
126 POST_CONTENTS,
de66a695 127 HOST_TABLE_OF_DEVICES,
55a82ab3
KJH
128};
129
130static const char* tcpa_pc_event_id_strings[] = {
de66a695 131 "",
55a82ab3
KJH
132 "SMBIOS",
133 "BIS Certificate",
134 "POST BIOS ",
135 "ESCD ",
136 "CMOS",
137 "NVRAM",
138 "Option ROM",
139 "Option ROM config",
de66a695
SM
140 "",
141 "Option ROM microcode ",
55a82ab3 142 "S-CRTM Version",
de66a695
SM
143 "S-CRTM Contents ",
144 "POST Contents ",
145 "Table of Devices",
55a82ab3
KJH
146};
147
55a82ab3
KJH
148/* returns pointer to start of pos. entry of tcg log */
149static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
150{
151 loff_t i;
d09cf7d7
KJH
152 struct tpm_bios_log *log = m->private;
153 void *addr = log->bios_event_log;
154 void *limit = log->bios_event_log_end;
55a82ab3
KJH
155 struct tcpa_event *event;
156
157 /* read over *pos measurements */
158 for (i = 0; i < *pos; i++) {
159 event = addr;
160
d09cf7d7 161 if ((addr + sizeof(struct tcpa_event)) < limit) {
55a82ab3
KJH
162 if (event->event_type == 0 && event->event_size == 0)
163 return NULL;
d09cf7d7 164 addr += sizeof(struct tcpa_event) + event->event_size;
55a82ab3
KJH
165 }
166 }
167
168 /* now check if current entry is valid */
d09cf7d7 169 if ((addr + sizeof(struct tcpa_event)) >= limit)
55a82ab3
KJH
170 return NULL;
171
172 event = addr;
173
174 if ((event->event_type == 0 && event->event_size == 0) ||
d09cf7d7 175 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
55a82ab3
KJH
176 return NULL;
177
178 return addr;
179}
180
181static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
182 loff_t *pos)
183{
184 struct tcpa_event *event = v;
d09cf7d7
KJH
185 struct tpm_bios_log *log = m->private;
186 void *limit = log->bios_event_log_end;
55a82ab3
KJH
187
188 v += sizeof(struct tcpa_event) + event->event_size;
189
190 /* now check if current entry is valid */
d09cf7d7 191 if ((v + sizeof(struct tcpa_event)) >= limit)
55a82ab3
KJH
192 return NULL;
193
194 event = v;
195
196 if (event->event_type == 0 && event->event_size == 0)
197 return NULL;
198
199 if ((event->event_type == 0 && event->event_size == 0) ||
d09cf7d7 200 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
55a82ab3
KJH
201 return NULL;
202
203 (*pos)++;
204 return v;
205}
206
207static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
208{
209}
210
211static int get_event_name(char *dest, struct tcpa_event *event,
212 unsigned char * event_entry)
213{
214 const char *name = "";
215 char data[40] = "";
216 int i, n_len = 0, d_len = 0;
de66a695 217 struct tcpa_pc_event *pc_event;
55a82ab3
KJH
218
219 switch(event->event_type) {
220 case PREBOOT:
221 case POST_CODE:
222 case UNUSED:
223 case NO_ACTION:
224 case SCRTM_CONTENTS:
225 case SCRTM_VERSION:
226 case CPU_MICROCODE:
227 case PLATFORM_CONFIG_FLAGS:
228 case TABLE_OF_DEVICES:
229 case COMPACT_HASH:
230 case IPL:
231 case IPL_PARTITION_DATA:
232 case NONHOST_CODE:
233 case NONHOST_CONFIG:
234 case NONHOST_INFO:
235 name = tcpa_event_type_strings[event->event_type];
236 n_len = strlen(name);
237 break;
238 case SEPARATOR:
239 case ACTION:
240 if (MAX_TEXT_EVENT > event->event_size) {
241 name = event_entry;
242 n_len = event->event_size;
243 }
244 break;
245 case EVENT_TAG:
de66a695 246 pc_event = (struct tcpa_pc_event *)event_entry;
55a82ab3
KJH
247
248 /* ToDo Row data -> Base64 */
249
de66a695 250 switch (pc_event->event_id) {
55a82ab3
KJH
251 case SMBIOS:
252 case BIS_CERT:
253 case CMOS:
254 case NVRAM:
255 case OPTION_ROM_EXEC:
256 case OPTION_ROM_CONFIG:
55a82ab3 257 case S_CRTM_VERSION:
de66a695 258 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
259 n_len = strlen(name);
260 break;
de66a695 261 /* hash data */
55a82ab3
KJH
262 case POST_BIOS_ROM:
263 case ESCD:
de66a695
SM
264 case OPTION_ROM_MICROCODE:
265 case S_CRTM_CONTENTS:
266 case POST_CONTENTS:
267 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
268 n_len = strlen(name);
269 for (i = 0; i < 20; i++)
de66a695
SM
270 d_len += sprintf(&data[2*i], "%02x",
271 pc_event->event_data[i]);
55a82ab3
KJH
272 break;
273 default:
274 break;
275 }
276 default:
277 break;
278 }
279
280 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
281 n_len, name, d_len, data);
282
283}
284
285static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
286{
44d7aff0
SM
287 struct tcpa_event *event = v;
288 char *data = v;
289 int i;
55a82ab3 290
44d7aff0 291 for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
55a82ab3
KJH
292 seq_putc(m, data[i]);
293
55a82ab3
KJH
294 return 0;
295}
296
297static int tpm_bios_measurements_release(struct inode *inode,
298 struct file *file)
299{
d09cf7d7
KJH
300 struct seq_file *seq = file->private_data;
301 struct tpm_bios_log *log = seq->private;
302
303 if (log) {
304 kfree(log->bios_event_log);
305 kfree(log);
55a82ab3 306 }
d09cf7d7 307
55a82ab3
KJH
308 return seq_release(inode, file);
309}
310
311static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
312{
313 int len = 0;
314 int i;
315 char *eventname;
316 struct tcpa_event *event = v;
317 unsigned char *event_entry =
318 (unsigned char *) (v + sizeof(struct tcpa_event));
319
320 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
321 if (!eventname) {
322 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
323 __func__);
324 return -EFAULT;
325 }
326
327 seq_printf(m, "%2d ", event->pcr_index);
328
329 /* 2nd: SHA1 */
330 for (i = 0; i < 20; i++)
331 seq_printf(m, "%02x", event->pcr_value[i]);
332
333 /* 3rd: event type identifier */
334 seq_printf(m, " %02x", event->event_type);
335
336 len += get_event_name(eventname, event, event_entry);
337
338 /* 4th: eventname <= max + \'0' delimiter */
339 seq_printf(m, " %s\n", eventname);
340
59e89f3a 341 kfree(eventname);
55a82ab3
KJH
342 return 0;
343}
344
345static struct seq_operations tpm_ascii_b_measurments_seqops = {
346 .start = tpm_bios_measurements_start,
347 .next = tpm_bios_measurements_next,
348 .stop = tpm_bios_measurements_stop,
349 .show = tpm_ascii_bios_measurements_show,
350};
351
352static struct seq_operations tpm_binary_b_measurments_seqops = {
353 .start = tpm_bios_measurements_start,
354 .next = tpm_bios_measurements_next,
355 .stop = tpm_bios_measurements_stop,
356 .show = tpm_binary_bios_measurements_show,
357};
358
359/* read binary bios log */
d09cf7d7 360static int read_log(struct tpm_bios_log *log)
55a82ab3
KJH
361{
362 struct acpi_tcpa *buff;
363 acpi_status status;
10296cb0 364 struct acpi_table_header *virt;
8b006db6 365 u64 len, start;
55a82ab3 366
d09cf7d7 367 if (log->bios_event_log != NULL) {
55a82ab3
KJH
368 printk(KERN_ERR
369 "%s: ERROR - Eventlog already initialized\n",
370 __func__);
371 return -EFAULT;
372 }
373
374 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
15a58ed1
AS
375 status = acpi_get_table(ACPI_SIG_TCPA, 1,
376 (struct acpi_table_header **)&buff);
55a82ab3
KJH
377
378 if (ACPI_FAILURE(status)) {
379 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
380 __func__);
381 return -EIO;
382 }
383
8b006db6
KJH
384 switch(buff->platform_class) {
385 case BIOS_SERVER:
386 len = buff->server.log_max_len;
387 start = buff->server.log_start_addr;
388 break;
389 case BIOS_CLIENT:
390 default:
391 len = buff->client.log_max_len;
392 start = buff->client.log_start_addr;
393 break;
394 }
395 if (!len) {
d09cf7d7 396 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
55a82ab3
KJH
397 return -EIO;
398 }
399
400 /* malloc EventLog space */
8b006db6 401 log->bios_event_log = kmalloc(len, GFP_KERNEL);
d09cf7d7 402 if (!log->bios_event_log) {
8b006db6
KJH
403 printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
404 __func__);
55a82ab3
KJH
405 return -ENOMEM;
406 }
407
8b006db6 408 log->bios_event_log_end = log->bios_event_log + len;
55a82ab3 409
15a58ed1 410 virt = acpi_os_map_memory(start, len);
55a82ab3 411
8b006db6 412 memcpy(log->bios_event_log, virt, len);
55a82ab3 413
8b006db6 414 acpi_os_unmap_memory(virt, len);
55a82ab3
KJH
415 return 0;
416}
417
418static int tpm_ascii_bios_measurements_open(struct inode *inode,
419 struct file *file)
420{
421 int err;
d09cf7d7
KJH
422 struct tpm_bios_log *log;
423 struct seq_file *seq;
55a82ab3 424
d09cf7d7
KJH
425 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
426 if (!log)
427 return -ENOMEM;
428
429 if ((err = read_log(log)))
178554ae 430 goto out_free;
55a82ab3
KJH
431
432 /* now register seq file */
d09cf7d7
KJH
433 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
434 if (!err) {
435 seq = file->private_data;
436 seq->private = log;
437 } else {
178554ae 438 goto out_free;
d09cf7d7 439 }
178554ae
JJ
440
441out:
d09cf7d7 442 return err;
178554ae
JJ
443out_free:
444 kfree(log->bios_event_log);
445 kfree(log);
446 goto out;
55a82ab3
KJH
447}
448
3bd60464 449static const struct file_operations tpm_ascii_bios_measurements_ops = {
55a82ab3
KJH
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;
d09cf7d7
KJH
460 struct tpm_bios_log *log;
461 struct seq_file *seq;
55a82ab3 462
d09cf7d7
KJH
463 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
464 if (!log)
465 return -ENOMEM;
466
467 if ((err = read_log(log)))
03ce1104 468 goto out_free;
55a82ab3
KJH
469
470 /* now register seq file */
d09cf7d7
KJH
471 err = seq_open(file, &tpm_binary_b_measurments_seqops);
472 if (!err) {
473 seq = file->private_data;
474 seq->private = log;
475 } else {
03ce1104 476 goto out_free;
d09cf7d7 477 }
03ce1104
RS
478
479out:
d09cf7d7 480 return err;
03ce1104
RS
481out_free:
482 kfree(log->bios_event_log);
483 kfree(log);
484 goto out;
55a82ab3
KJH
485}
486
3bd60464 487static const struct file_operations tpm_binary_bios_measurements_ops = {
55a82ab3
KJH
488 .open = tpm_binary_bios_measurements_open,
489 .read = seq_read,
490 .llseek = seq_lseek,
491 .release = tpm_bios_measurements_release,
492};
493
ca4a031f
AM
494static int is_bad(void *p)
495{
496 if (!p)
497 return 1;
498 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
499 return 1;
500 return 0;
501}
502
55a82ab3
KJH
503struct dentry **tpm_bios_log_setup(char *name)
504{
505 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
506
507 tpm_dir = securityfs_create_dir(name, NULL);
ca4a031f 508 if (is_bad(tpm_dir))
55a82ab3
KJH
509 goto out;
510
511 bin_file =
512 securityfs_create_file("binary_bios_measurements",
513 S_IRUSR | S_IRGRP, tpm_dir, NULL,
514 &tpm_binary_bios_measurements_ops);
ca4a031f 515 if (is_bad(bin_file))
55a82ab3
KJH
516 goto out_tpm;
517
518 ascii_file =
519 securityfs_create_file("ascii_bios_measurements",
520 S_IRUSR | S_IRGRP, tpm_dir, NULL,
521 &tpm_ascii_bios_measurements_ops);
ca4a031f 522 if (is_bad(ascii_file))
55a82ab3
KJH
523 goto out_bin;
524
525 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
526 if (!ret)
527 goto out_ascii;
528
529 ret[0] = ascii_file;
530 ret[1] = bin_file;
531 ret[2] = tpm_dir;
532
533 return ret;
534
535out_ascii:
536 securityfs_remove(ascii_file);
537out_bin:
538 securityfs_remove(bin_file);
539out_tpm:
540 securityfs_remove(tpm_dir);
541out:
542 return NULL;
543}
544EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
545
546void tpm_bios_log_teardown(struct dentry **lst)
547{
548 int i;
549
550 for (i = 0; i < 3; i++)
551 securityfs_remove(lst[i]);
552}
553EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
7bcee5b8 554MODULE_LICENSE("GPL");