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