TPM: sysfs functions consolidation
[deliverable/linux.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>
26#include <acpi/actypes.h>
27#include <acpi/actbl.h>
28#include "tpm.h"
29
30#define TCG_EVENT_NAME_LEN_MAX 255
31#define MAX_TEXT_EVENT 1000 /* Max event string length */
32#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
33
8b006db6
KJH
34enum bios_platform_class {
35 BIOS_CLIENT = 0x00,
36 BIOS_SERVER = 0x01,
37};
38
d09cf7d7
KJH
39struct tpm_bios_log {
40 void *bios_event_log;
41 void *bios_event_log_end;
42};
43
55a82ab3
KJH
44struct acpi_tcpa {
45 struct acpi_table_header hdr;
8b006db6
KJH
46 u16 platform_class;
47 union {
48 struct client_hdr {
49 u32 log_max_len __attribute__ ((packed));
50 u64 log_start_addr __attribute__ ((packed));
51 } client;
52 struct server_hdr {
53 u16 reserved;
54 u64 log_max_len __attribute__ ((packed));
55 u64 log_start_addr __attribute__ ((packed));
56 } server;
57 };
55a82ab3
KJH
58};
59
60struct tcpa_event {
61 u32 pcr_index;
62 u32 event_type;
63 u8 pcr_value[20]; /* SHA1 */
64 u32 event_size;
65 u8 event_data[0];
66};
67
68enum tcpa_event_types {
69 PREBOOT = 0,
70 POST_CODE,
71 UNUSED,
72 NO_ACTION,
73 SEPARATOR,
74 ACTION,
75 EVENT_TAG,
76 SCRTM_CONTENTS,
77 SCRTM_VERSION,
78 CPU_MICROCODE,
79 PLATFORM_CONFIG_FLAGS,
80 TABLE_OF_DEVICES,
81 COMPACT_HASH,
82 IPL,
83 IPL_PARTITION_DATA,
84 NONHOST_CODE,
85 NONHOST_CONFIG,
86 NONHOST_INFO,
87};
88
89static const char* tcpa_event_type_strings[] = {
90 "PREBOOT",
91 "POST CODE",
92 "",
93 "NO ACTION",
94 "SEPARATOR",
95 "ACTION",
96 "EVENT TAG",
97 "S-CRTM Contents",
98 "S-CRTM Version",
99 "CPU Microcode",
100 "Platform Config Flags",
101 "Table of Devices",
102 "Compact Hash",
103 "IPL",
104 "IPL Partition Data",
105 "Non-Host Code",
106 "Non-Host Config",
107 "Non-Host Info"
108};
109
de66a695
SM
110struct tcpa_pc_event {
111 u32 event_id;
112 u32 event_size;
113 u8 event_data[0];
114};
115
55a82ab3
KJH
116enum tcpa_pc_event_ids {
117 SMBIOS = 1,
118 BIS_CERT,
119 POST_BIOS_ROM,
120 ESCD,
121 CMOS,
122 NVRAM,
123 OPTION_ROM_EXEC,
124 OPTION_ROM_CONFIG,
de66a695 125 OPTION_ROM_MICROCODE = 10,
55a82ab3
KJH
126 S_CRTM_VERSION,
127 S_CRTM_CONTENTS,
128 POST_CONTENTS,
de66a695 129 HOST_TABLE_OF_DEVICES,
55a82ab3
KJH
130};
131
132static const char* tcpa_pc_event_id_strings[] = {
de66a695 133 "",
55a82ab3
KJH
134 "SMBIOS",
135 "BIS Certificate",
136 "POST BIOS ",
137 "ESCD ",
138 "CMOS",
139 "NVRAM",
140 "Option ROM",
141 "Option ROM config",
de66a695
SM
142 "",
143 "Option ROM microcode ",
55a82ab3 144 "S-CRTM Version",
de66a695
SM
145 "S-CRTM Contents ",
146 "POST Contents ",
147 "Table of Devices",
55a82ab3
KJH
148};
149
55a82ab3
KJH
150/* returns pointer to start of pos. entry of tcg log */
151static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
152{
153 loff_t i;
d09cf7d7
KJH
154 struct tpm_bios_log *log = m->private;
155 void *addr = log->bios_event_log;
156 void *limit = log->bios_event_log_end;
55a82ab3
KJH
157 struct tcpa_event *event;
158
159 /* read over *pos measurements */
160 for (i = 0; i < *pos; i++) {
161 event = addr;
162
d09cf7d7 163 if ((addr + sizeof(struct tcpa_event)) < limit) {
55a82ab3
KJH
164 if (event->event_type == 0 && event->event_size == 0)
165 return NULL;
d09cf7d7 166 addr += sizeof(struct tcpa_event) + event->event_size;
55a82ab3
KJH
167 }
168 }
169
170 /* now check if current entry is valid */
d09cf7d7 171 if ((addr + sizeof(struct tcpa_event)) >= limit)
55a82ab3
KJH
172 return NULL;
173
174 event = addr;
175
176 if ((event->event_type == 0 && event->event_size == 0) ||
d09cf7d7 177 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
55a82ab3
KJH
178 return NULL;
179
180 return addr;
181}
182
183static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
184 loff_t *pos)
185{
186 struct tcpa_event *event = v;
d09cf7d7
KJH
187 struct tpm_bios_log *log = m->private;
188 void *limit = log->bios_event_log_end;
55a82ab3
KJH
189
190 v += sizeof(struct tcpa_event) + event->event_size;
191
192 /* now check if current entry is valid */
d09cf7d7 193 if ((v + sizeof(struct tcpa_event)) >= limit)
55a82ab3
KJH
194 return NULL;
195
196 event = v;
197
198 if (event->event_type == 0 && event->event_size == 0)
199 return NULL;
200
201 if ((event->event_type == 0 && event->event_size == 0) ||
d09cf7d7 202 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
55a82ab3
KJH
203 return NULL;
204
205 (*pos)++;
206 return v;
207}
208
209static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
210{
211}
212
213static int get_event_name(char *dest, struct tcpa_event *event,
214 unsigned char * event_entry)
215{
216 const char *name = "";
217 char data[40] = "";
218 int i, n_len = 0, d_len = 0;
de66a695 219 struct tcpa_pc_event *pc_event;
55a82ab3
KJH
220
221 switch(event->event_type) {
222 case PREBOOT:
223 case POST_CODE:
224 case UNUSED:
225 case NO_ACTION:
226 case SCRTM_CONTENTS:
227 case SCRTM_VERSION:
228 case CPU_MICROCODE:
229 case PLATFORM_CONFIG_FLAGS:
230 case TABLE_OF_DEVICES:
231 case COMPACT_HASH:
232 case IPL:
233 case IPL_PARTITION_DATA:
234 case NONHOST_CODE:
235 case NONHOST_CONFIG:
236 case NONHOST_INFO:
237 name = tcpa_event_type_strings[event->event_type];
238 n_len = strlen(name);
239 break;
240 case SEPARATOR:
241 case ACTION:
242 if (MAX_TEXT_EVENT > event->event_size) {
243 name = event_entry;
244 n_len = event->event_size;
245 }
246 break;
247 case EVENT_TAG:
de66a695 248 pc_event = (struct tcpa_pc_event *)event_entry;
55a82ab3
KJH
249
250 /* ToDo Row data -> Base64 */
251
de66a695 252 switch (pc_event->event_id) {
55a82ab3
KJH
253 case SMBIOS:
254 case BIS_CERT:
255 case CMOS:
256 case NVRAM:
257 case OPTION_ROM_EXEC:
258 case OPTION_ROM_CONFIG:
55a82ab3 259 case S_CRTM_VERSION:
de66a695 260 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
261 n_len = strlen(name);
262 break;
de66a695 263 /* hash data */
55a82ab3
KJH
264 case POST_BIOS_ROM:
265 case ESCD:
de66a695
SM
266 case OPTION_ROM_MICROCODE:
267 case S_CRTM_CONTENTS:
268 case POST_CONTENTS:
269 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
270 n_len = strlen(name);
271 for (i = 0; i < 20; i++)
de66a695
SM
272 d_len += sprintf(&data[2*i], "%02x",
273 pc_event->event_data[i]);
55a82ab3
KJH
274 break;
275 default:
276 break;
277 }
278 default:
279 break;
280 }
281
282 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
283 n_len, name, d_len, data);
284
285}
286
287static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
288{
44d7aff0
SM
289 struct tcpa_event *event = v;
290 char *data = v;
291 int i;
55a82ab3 292
44d7aff0 293 for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
55a82ab3
KJH
294 seq_putc(m, data[i]);
295
55a82ab3
KJH
296 return 0;
297}
298
299static int tpm_bios_measurements_release(struct inode *inode,
300 struct file *file)
301{
d09cf7d7
KJH
302 struct seq_file *seq = file->private_data;
303 struct tpm_bios_log *log = seq->private;
304
305 if (log) {
306 kfree(log->bios_event_log);
307 kfree(log);
55a82ab3 308 }
d09cf7d7 309
55a82ab3
KJH
310 return seq_release(inode, file);
311}
312
313static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
314{
315 int len = 0;
316 int i;
317 char *eventname;
318 struct tcpa_event *event = v;
319 unsigned char *event_entry =
320 (unsigned char *) (v + sizeof(struct tcpa_event));
321
322 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
323 if (!eventname) {
324 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
325 __func__);
326 return -EFAULT;
327 }
328
329 seq_printf(m, "%2d ", event->pcr_index);
330
331 /* 2nd: SHA1 */
332 for (i = 0; i < 20; i++)
333 seq_printf(m, "%02x", event->pcr_value[i]);
334
335 /* 3rd: event type identifier */
336 seq_printf(m, " %02x", event->event_type);
337
338 len += get_event_name(eventname, event, event_entry);
339
340 /* 4th: eventname <= max + \'0' delimiter */
341 seq_printf(m, " %s\n", eventname);
342
59e89f3a 343 kfree(eventname);
55a82ab3
KJH
344 return 0;
345}
346
347static struct seq_operations tpm_ascii_b_measurments_seqops = {
348 .start = tpm_bios_measurements_start,
349 .next = tpm_bios_measurements_next,
350 .stop = tpm_bios_measurements_stop,
351 .show = tpm_ascii_bios_measurements_show,
352};
353
354static struct seq_operations tpm_binary_b_measurments_seqops = {
355 .start = tpm_bios_measurements_start,
356 .next = tpm_bios_measurements_next,
357 .stop = tpm_bios_measurements_stop,
358 .show = tpm_binary_bios_measurements_show,
359};
360
361/* read binary bios log */
d09cf7d7 362static int read_log(struct tpm_bios_log *log)
55a82ab3
KJH
363{
364 struct acpi_tcpa *buff;
365 acpi_status status;
10296cb0 366 struct acpi_table_header *virt;
8b006db6 367 u64 len, start;
55a82ab3 368
d09cf7d7 369 if (log->bios_event_log != NULL) {
55a82ab3
KJH
370 printk(KERN_ERR
371 "%s: ERROR - Eventlog already initialized\n",
372 __func__);
373 return -EFAULT;
374 }
375
376 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
15a58ed1
AS
377 status = acpi_get_table(ACPI_SIG_TCPA, 1,
378 (struct acpi_table_header **)&buff);
55a82ab3
KJH
379
380 if (ACPI_FAILURE(status)) {
381 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
382 __func__);
383 return -EIO;
384 }
385
8b006db6
KJH
386 switch(buff->platform_class) {
387 case BIOS_SERVER:
388 len = buff->server.log_max_len;
389 start = buff->server.log_start_addr;
390 break;
391 case BIOS_CLIENT:
392 default:
393 len = buff->client.log_max_len;
394 start = buff->client.log_start_addr;
395 break;
396 }
397 if (!len) {
d09cf7d7 398 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
55a82ab3
KJH
399 return -EIO;
400 }
401
402 /* malloc EventLog space */
8b006db6 403 log->bios_event_log = kmalloc(len, GFP_KERNEL);
d09cf7d7 404 if (!log->bios_event_log) {
8b006db6
KJH
405 printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
406 __func__);
55a82ab3
KJH
407 return -ENOMEM;
408 }
409
8b006db6 410 log->bios_event_log_end = log->bios_event_log + len;
55a82ab3 411
15a58ed1 412 virt = acpi_os_map_memory(start, len);
55a82ab3 413
8b006db6 414 memcpy(log->bios_event_log, virt, len);
55a82ab3 415
8b006db6 416 acpi_os_unmap_memory(virt, len);
55a82ab3
KJH
417 return 0;
418}
419
420static int tpm_ascii_bios_measurements_open(struct inode *inode,
421 struct file *file)
422{
423 int err;
d09cf7d7
KJH
424 struct tpm_bios_log *log;
425 struct seq_file *seq;
55a82ab3 426
d09cf7d7
KJH
427 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
428 if (!log)
429 return -ENOMEM;
430
431 if ((err = read_log(log)))
178554ae 432 goto out_free;
55a82ab3
KJH
433
434 /* now register seq file */
d09cf7d7
KJH
435 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
436 if (!err) {
437 seq = file->private_data;
438 seq->private = log;
439 } else {
178554ae 440 goto out_free;
d09cf7d7 441 }
178554ae
JJ
442
443out:
d09cf7d7 444 return err;
178554ae
JJ
445out_free:
446 kfree(log->bios_event_log);
447 kfree(log);
448 goto out;
55a82ab3
KJH
449}
450
3bd60464 451static const struct file_operations tpm_ascii_bios_measurements_ops = {
55a82ab3
KJH
452 .open = tpm_ascii_bios_measurements_open,
453 .read = seq_read,
454 .llseek = seq_lseek,
455 .release = tpm_bios_measurements_release,
456};
457
458static int tpm_binary_bios_measurements_open(struct inode *inode,
459 struct file *file)
460{
461 int err;
d09cf7d7
KJH
462 struct tpm_bios_log *log;
463 struct seq_file *seq;
55a82ab3 464
d09cf7d7
KJH
465 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
466 if (!log)
467 return -ENOMEM;
468
469 if ((err = read_log(log)))
03ce1104 470 goto out_free;
55a82ab3
KJH
471
472 /* now register seq file */
d09cf7d7
KJH
473 err = seq_open(file, &tpm_binary_b_measurments_seqops);
474 if (!err) {
475 seq = file->private_data;
476 seq->private = log;
477 } else {
03ce1104 478 goto out_free;
d09cf7d7 479 }
03ce1104
RS
480
481out:
d09cf7d7 482 return err;
03ce1104
RS
483out_free:
484 kfree(log->bios_event_log);
485 kfree(log);
486 goto out;
55a82ab3
KJH
487}
488
3bd60464 489static const struct file_operations tpm_binary_bios_measurements_ops = {
55a82ab3
KJH
490 .open = tpm_binary_bios_measurements_open,
491 .read = seq_read,
492 .llseek = seq_lseek,
493 .release = tpm_bios_measurements_release,
494};
495
ca4a031f
AM
496static int is_bad(void *p)
497{
498 if (!p)
499 return 1;
500 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
501 return 1;
502 return 0;
503}
504
55a82ab3
KJH
505struct dentry **tpm_bios_log_setup(char *name)
506{
507 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
508
509 tpm_dir = securityfs_create_dir(name, NULL);
ca4a031f 510 if (is_bad(tpm_dir))
55a82ab3
KJH
511 goto out;
512
513 bin_file =
514 securityfs_create_file("binary_bios_measurements",
515 S_IRUSR | S_IRGRP, tpm_dir, NULL,
516 &tpm_binary_bios_measurements_ops);
ca4a031f 517 if (is_bad(bin_file))
55a82ab3
KJH
518 goto out_tpm;
519
520 ascii_file =
521 securityfs_create_file("ascii_bios_measurements",
522 S_IRUSR | S_IRGRP, tpm_dir, NULL,
523 &tpm_ascii_bios_measurements_ops);
ca4a031f 524 if (is_bad(ascii_file))
55a82ab3
KJH
525 goto out_bin;
526
527 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
528 if (!ret)
529 goto out_ascii;
530
531 ret[0] = ascii_file;
532 ret[1] = bin_file;
533 ret[2] = tpm_dir;
534
535 return ret;
536
537out_ascii:
538 securityfs_remove(ascii_file);
539out_bin:
540 securityfs_remove(bin_file);
541out_tpm:
542 securityfs_remove(tpm_dir);
543out:
544 return NULL;
545}
546EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
547
548void tpm_bios_log_teardown(struct dentry **lst)
549{
550 int i;
551
552 for (i = 0; i < 3; i++)
553 securityfs_remove(lst[i]);
554}
555EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
7bcee5b8 556MODULE_LICENSE("GPL");
This page took 0.356232 seconds and 5 git commands to generate.