seq_file: constify seq_operations
[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>
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 = "";
fbaa5869
EP
215 /* 41 so there is room for 40 data and 1 nul */
216 char data[41] = "";
55a82ab3 217 int i, n_len = 0, d_len = 0;
de66a695 218 struct tcpa_pc_event *pc_event;
55a82ab3
KJH
219
220 switch(event->event_type) {
221 case PREBOOT:
222 case POST_CODE:
223 case UNUSED:
224 case NO_ACTION:
225 case SCRTM_CONTENTS:
226 case SCRTM_VERSION:
227 case CPU_MICROCODE:
228 case PLATFORM_CONFIG_FLAGS:
229 case TABLE_OF_DEVICES:
230 case COMPACT_HASH:
231 case IPL:
232 case IPL_PARTITION_DATA:
233 case NONHOST_CODE:
234 case NONHOST_CONFIG:
235 case NONHOST_INFO:
236 name = tcpa_event_type_strings[event->event_type];
237 n_len = strlen(name);
238 break;
239 case SEPARATOR:
240 case ACTION:
241 if (MAX_TEXT_EVENT > event->event_size) {
242 name = event_entry;
243 n_len = event->event_size;
244 }
245 break;
246 case EVENT_TAG:
de66a695 247 pc_event = (struct tcpa_pc_event *)event_entry;
55a82ab3
KJH
248
249 /* ToDo Row data -> Base64 */
250
de66a695 251 switch (pc_event->event_id) {
55a82ab3
KJH
252 case SMBIOS:
253 case BIS_CERT:
254 case CMOS:
255 case NVRAM:
256 case OPTION_ROM_EXEC:
257 case OPTION_ROM_CONFIG:
55a82ab3 258 case S_CRTM_VERSION:
de66a695 259 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
260 n_len = strlen(name);
261 break;
de66a695 262 /* hash data */
55a82ab3
KJH
263 case POST_BIOS_ROM:
264 case ESCD:
de66a695
SM
265 case OPTION_ROM_MICROCODE:
266 case S_CRTM_CONTENTS:
267 case POST_CONTENTS:
268 name = tcpa_pc_event_id_strings[pc_event->event_id];
55a82ab3
KJH
269 n_len = strlen(name);
270 for (i = 0; i < 20; i++)
de66a695
SM
271 d_len += sprintf(&data[2*i], "%02x",
272 pc_event->event_data[i]);
55a82ab3
KJH
273 break;
274 default:
275 break;
276 }
277 default:
278 break;
279 }
280
281 return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
282 n_len, name, d_len, data);
283
284}
285
286static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
287{
44d7aff0
SM
288 struct tcpa_event *event = v;
289 char *data = v;
290 int i;
55a82ab3 291
44d7aff0 292 for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
55a82ab3
KJH
293 seq_putc(m, data[i]);
294
55a82ab3
KJH
295 return 0;
296}
297
298static int tpm_bios_measurements_release(struct inode *inode,
299 struct file *file)
300{
d09cf7d7
KJH
301 struct seq_file *seq = file->private_data;
302 struct tpm_bios_log *log = seq->private;
303
304 if (log) {
305 kfree(log->bios_event_log);
306 kfree(log);
55a82ab3 307 }
d09cf7d7 308
55a82ab3
KJH
309 return seq_release(inode, file);
310}
311
312static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
313{
314 int len = 0;
315 int i;
316 char *eventname;
317 struct tcpa_event *event = v;
318 unsigned char *event_entry =
319 (unsigned char *) (v + sizeof(struct tcpa_event));
320
321 eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
322 if (!eventname) {
323 printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
324 __func__);
325 return -EFAULT;
326 }
327
328 seq_printf(m, "%2d ", event->pcr_index);
329
330 /* 2nd: SHA1 */
331 for (i = 0; i < 20; i++)
332 seq_printf(m, "%02x", event->pcr_value[i]);
333
334 /* 3rd: event type identifier */
335 seq_printf(m, " %02x", event->event_type);
336
337 len += get_event_name(eventname, event, event_entry);
338
339 /* 4th: eventname <= max + \'0' delimiter */
340 seq_printf(m, " %s\n", eventname);
341
59e89f3a 342 kfree(eventname);
55a82ab3
KJH
343 return 0;
344}
345
88e9d34c 346static const struct seq_operations tpm_ascii_b_measurments_seqops = {
55a82ab3
KJH
347 .start = tpm_bios_measurements_start,
348 .next = tpm_bios_measurements_next,
349 .stop = tpm_bios_measurements_stop,
350 .show = tpm_ascii_bios_measurements_show,
351};
352
88e9d34c 353static const struct seq_operations tpm_binary_b_measurments_seqops = {
55a82ab3
KJH
354 .start = tpm_bios_measurements_start,
355 .next = tpm_bios_measurements_next,
356 .stop = tpm_bios_measurements_stop,
357 .show = tpm_binary_bios_measurements_show,
358};
359
360/* read binary bios log */
d09cf7d7 361static int read_log(struct tpm_bios_log *log)
55a82ab3
KJH
362{
363 struct acpi_tcpa *buff;
364 acpi_status status;
10296cb0 365 struct acpi_table_header *virt;
8b006db6 366 u64 len, start;
55a82ab3 367
d09cf7d7 368 if (log->bios_event_log != NULL) {
55a82ab3
KJH
369 printk(KERN_ERR
370 "%s: ERROR - Eventlog already initialized\n",
371 __func__);
372 return -EFAULT;
373 }
374
375 /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
15a58ed1
AS
376 status = acpi_get_table(ACPI_SIG_TCPA, 1,
377 (struct acpi_table_header **)&buff);
55a82ab3
KJH
378
379 if (ACPI_FAILURE(status)) {
380 printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
381 __func__);
382 return -EIO;
383 }
384
8b006db6
KJH
385 switch(buff->platform_class) {
386 case BIOS_SERVER:
387 len = buff->server.log_max_len;
388 start = buff->server.log_start_addr;
389 break;
390 case BIOS_CLIENT:
391 default:
392 len = buff->client.log_max_len;
393 start = buff->client.log_start_addr;
394 break;
395 }
396 if (!len) {
d09cf7d7 397 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
55a82ab3
KJH
398 return -EIO;
399 }
400
401 /* malloc EventLog space */
8b006db6 402 log->bios_event_log = kmalloc(len, GFP_KERNEL);
d09cf7d7 403 if (!log->bios_event_log) {
8b006db6
KJH
404 printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
405 __func__);
55a82ab3
KJH
406 return -ENOMEM;
407 }
408
8b006db6 409 log->bios_event_log_end = log->bios_event_log + len;
55a82ab3 410
15a58ed1 411 virt = acpi_os_map_memory(start, len);
55a82ab3 412
8b006db6 413 memcpy(log->bios_event_log, virt, len);
55a82ab3 414
8b006db6 415 acpi_os_unmap_memory(virt, len);
55a82ab3
KJH
416 return 0;
417}
418
419static int tpm_ascii_bios_measurements_open(struct inode *inode,
420 struct file *file)
421{
422 int err;
d09cf7d7
KJH
423 struct tpm_bios_log *log;
424 struct seq_file *seq;
55a82ab3 425
d09cf7d7
KJH
426 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
427 if (!log)
428 return -ENOMEM;
429
430 if ((err = read_log(log)))
178554ae 431 goto out_free;
55a82ab3
KJH
432
433 /* now register seq file */
d09cf7d7
KJH
434 err = seq_open(file, &tpm_ascii_b_measurments_seqops);
435 if (!err) {
436 seq = file->private_data;
437 seq->private = log;
438 } else {
178554ae 439 goto out_free;
d09cf7d7 440 }
178554ae
JJ
441
442out:
d09cf7d7 443 return err;
178554ae
JJ
444out_free:
445 kfree(log->bios_event_log);
446 kfree(log);
447 goto out;
55a82ab3
KJH
448}
449
3bd60464 450static const struct file_operations tpm_ascii_bios_measurements_ops = {
55a82ab3
KJH
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;
d09cf7d7
KJH
461 struct tpm_bios_log *log;
462 struct seq_file *seq;
55a82ab3 463
d09cf7d7
KJH
464 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
465 if (!log)
466 return -ENOMEM;
467
468 if ((err = read_log(log)))
03ce1104 469 goto out_free;
55a82ab3
KJH
470
471 /* now register seq file */
d09cf7d7
KJH
472 err = seq_open(file, &tpm_binary_b_measurments_seqops);
473 if (!err) {
474 seq = file->private_data;
475 seq->private = log;
476 } else {
03ce1104 477 goto out_free;
d09cf7d7 478 }
03ce1104
RS
479
480out:
d09cf7d7 481 return err;
03ce1104
RS
482out_free:
483 kfree(log->bios_event_log);
484 kfree(log);
485 goto out;
55a82ab3
KJH
486}
487
3bd60464 488static const struct file_operations tpm_binary_bios_measurements_ops = {
55a82ab3
KJH
489 .open = tpm_binary_bios_measurements_open,
490 .read = seq_read,
491 .llseek = seq_lseek,
492 .release = tpm_bios_measurements_release,
493};
494
ca4a031f
AM
495static int is_bad(void *p)
496{
497 if (!p)
498 return 1;
499 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
500 return 1;
501 return 0;
502}
503
55a82ab3
KJH
504struct dentry **tpm_bios_log_setup(char *name)
505{
506 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
507
508 tpm_dir = securityfs_create_dir(name, NULL);
ca4a031f 509 if (is_bad(tpm_dir))
55a82ab3
KJH
510 goto out;
511
512 bin_file =
513 securityfs_create_file("binary_bios_measurements",
514 S_IRUSR | S_IRGRP, tpm_dir, NULL,
515 &tpm_binary_bios_measurements_ops);
ca4a031f 516 if (is_bad(bin_file))
55a82ab3
KJH
517 goto out_tpm;
518
519 ascii_file =
520 securityfs_create_file("ascii_bios_measurements",
521 S_IRUSR | S_IRGRP, tpm_dir, NULL,
522 &tpm_ascii_bios_measurements_ops);
ca4a031f 523 if (is_bad(ascii_file))
55a82ab3
KJH
524 goto out_bin;
525
526 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
527 if (!ret)
528 goto out_ascii;
529
530 ret[0] = ascii_file;
531 ret[1] = bin_file;
532 ret[2] = tpm_dir;
533
534 return ret;
535
536out_ascii:
537 securityfs_remove(ascii_file);
538out_bin:
539 securityfs_remove(bin_file);
540out_tpm:
541 securityfs_remove(tpm_dir);
542out:
543 return NULL;
544}
545EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
546
547void tpm_bios_log_teardown(struct dentry **lst)
548{
549 int i;
550
551 for (i = 0; i < 3; i++)
552 securityfs_remove(lst[i]);
553}
554EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
7bcee5b8 555MODULE_LICENSE("GPL");
This page took 0.621724 seconds and 5 git commands to generate.