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 32enum bios_platform_class { 33 BIOS_CLIENT = 0x00, 34 BIOS_SERVER = 0x01, 35}; 36 37struct tpm_bios_log { 38 void *bios_event_log; 39 void *bios_event_log_end; 40}; 41 42struct acpi_tcpa { 43 struct acpi_table_header hdr; 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 }; 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 108struct tcpa_pc_event { 109 u32 event_id; 110 u32 event_size; 111 u8 event_data[0]; 112}; 113 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, 123 OPTION_ROM_MICROCODE = 10, 124 S_CRTM_VERSION, 125 S_CRTM_CONTENTS, 126 POST_CONTENTS, 127 HOST_TABLE_OF_DEVICES, 128}; 129 130static const char* tcpa_pc_event_id_strings[] = { 131 "", 132 "SMBIOS", 133 "BIS Certificate", 134 "POST BIOS ", 135 "ESCD ", 136 "CMOS", 137 "NVRAM", 138 "Option ROM", 139 "Option ROM config", 140 "", 141 "Option ROM microcode ", 142 "S-CRTM Version", 143 "S-CRTM Contents ", 144 "POST Contents ", 145 "Table of Devices", 146}; 147 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; 152 struct tpm_bios_log *log = m->private; 153 void *addr = log->bios_event_log; 154 void *limit = log->bios_event_log_end; 155 struct tcpa_event *event; 156 157 /* read over *pos measurements */ 158 for (i = 0; i < *pos; i++) { 159 event = addr; 160 161 if ((addr + sizeof(struct tcpa_event)) < limit) { 162 if (event->event_type == 0 && event->event_size == 0) 163 return NULL; 164 addr += sizeof(struct tcpa_event) + event->event_size; 165 } 166 } 167 168 /* now check if current entry is valid */ 169 if ((addr + sizeof(struct tcpa_event)) >= limit) 170 return NULL; 171 172 event = addr; 173 174 if ((event->event_type == 0 && event->event_size == 0) || 175 ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit)) 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; 185 struct tpm_bios_log *log = m->private; 186 void *limit = log->bios_event_log_end; 187 188 v += sizeof(struct tcpa_event) + event->event_size; 189 190 /* now check if current entry is valid */ 191 if ((v + sizeof(struct tcpa_event)) >= limit) 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) || 200 ((v + sizeof(struct tcpa_event) + event->event_size) >= limit)) 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; 217 struct tcpa_pc_event *pc_event; 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: 246 pc_event = (struct tcpa_pc_event *)event_entry; 247 248 /* ToDo Row data -> Base64 */ 249 250 switch (pc_event->event_id) { 251 case SMBIOS: 252 case BIS_CERT: 253 case CMOS: 254 case NVRAM: 255 case OPTION_ROM_EXEC: 256 case OPTION_ROM_CONFIG: 257 case S_CRTM_VERSION: 258 name = tcpa_pc_event_id_strings[pc_event->event_id]; 259 n_len = strlen(name); 260 break; 261 /* hash data */ 262 case POST_BIOS_ROM: 263 case ESCD: 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]; 268 n_len = strlen(name); 269 for (i = 0; i < 20; i++) 270 d_len += sprintf(&data[2*i], "%02x", 271 pc_event->event_data[i]); 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{ 287 struct tcpa_event *event = v; 288 char *data = v; 289 int i; 290 291 for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++) 292 seq_putc(m, data[i]); 293 294 return 0; 295} 296 297static int tpm_bios_measurements_release(struct inode *inode, 298 struct file *file) 299{ 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); 306 } 307 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 341 kfree(eventname); 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 */ 360static int read_log(struct tpm_bios_log *log) 361{ 362 struct acpi_tcpa *buff; 363 acpi_status status; 364 struct acpi_table_header *virt; 365 u64 len, start; 366 367 if (log->bios_event_log != NULL) { 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) */ 375 status = acpi_get_table(ACPI_SIG_TCPA, 1, 376 (struct acpi_table_header **)&buff); 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 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) { 396 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); 397 return -EIO; 398 } 399 400 /* malloc EventLog space */ 401 log->bios_event_log = kmalloc(len, GFP_KERNEL); 402 if (!log->bios_event_log) { 403 printk("%s: ERROR - Not enough Memory for BIOS measurements\n", 404 __func__); 405 return -ENOMEM; 406 } 407 408 log->bios_event_log_end = log->bios_event_log + len; 409 410 virt = acpi_os_map_memory(start, len); 411 412 memcpy(log->bios_event_log, virt, len); 413 414 acpi_os_unmap_memory(virt, len); 415 return 0; 416} 417 418static int tpm_ascii_bios_measurements_open(struct inode *inode, 419 struct file *file) 420{ 421 int err; 422 struct tpm_bios_log *log; 423 struct seq_file *seq; 424 425 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); 426 if (!log) 427 return -ENOMEM; 428 429 if ((err = read_log(log))) 430 return err; 431 432 /* now register seq file */ 433 err = seq_open(file, &tpm_ascii_b_measurments_seqops); 434 if (!err) { 435 seq = file->private_data; 436 seq->private = log; 437 } else { 438 kfree(log->bios_event_log); 439 kfree(log); 440 } 441 return err; 442} 443 444const struct file_operations tpm_ascii_bios_measurements_ops = { 445 .open = tpm_ascii_bios_measurements_open, 446 .read = seq_read, 447 .llseek = seq_lseek, 448 .release = tpm_bios_measurements_release, 449}; 450 451static int tpm_binary_bios_measurements_open(struct inode *inode, 452 struct file *file) 453{ 454 int err; 455 struct tpm_bios_log *log; 456 struct seq_file *seq; 457 458 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); 459 if (!log) 460 return -ENOMEM; 461 462 if ((err = read_log(log))) 463 return err; 464 465 /* now register seq file */ 466 err = seq_open(file, &tpm_binary_b_measurments_seqops); 467 if (!err) { 468 seq = file->private_data; 469 seq->private = log; 470 } else { 471 kfree(log->bios_event_log); 472 kfree(log); 473 } 474 return err; 475} 476 477const struct file_operations tpm_binary_bios_measurements_ops = { 478 .open = tpm_binary_bios_measurements_open, 479 .read = seq_read, 480 .llseek = seq_lseek, 481 .release = tpm_bios_measurements_release, 482}; 483 484static int is_bad(void *p) 485{ 486 if (!p) 487 return 1; 488 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV)) 489 return 1; 490 return 0; 491} 492 493struct dentry **tpm_bios_log_setup(char *name) 494{ 495 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; 496 497 tpm_dir = securityfs_create_dir(name, NULL); 498 if (is_bad(tpm_dir)) 499 goto out; 500 501 bin_file = 502 securityfs_create_file("binary_bios_measurements", 503 S_IRUSR | S_IRGRP, tpm_dir, NULL, 504 &tpm_binary_bios_measurements_ops); 505 if (is_bad(bin_file)) 506 goto out_tpm; 507 508 ascii_file = 509 securityfs_create_file("ascii_bios_measurements", 510 S_IRUSR | S_IRGRP, tpm_dir, NULL, 511 &tpm_ascii_bios_measurements_ops); 512 if (is_bad(ascii_file)) 513 goto out_bin; 514 515 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); 516 if (!ret) 517 goto out_ascii; 518 519 ret[0] = ascii_file; 520 ret[1] = bin_file; 521 ret[2] = tpm_dir; 522 523 return ret; 524 525out_ascii: 526 securityfs_remove(ascii_file); 527out_bin: 528 securityfs_remove(bin_file); 529out_tpm: 530 securityfs_remove(tpm_dir); 531out: 532 return NULL; 533} 534EXPORT_SYMBOL_GPL(tpm_bios_log_setup); 535 536void tpm_bios_log_teardown(struct dentry **lst) 537{ 538 int i; 539 540 for (i = 0; i < 3; i++) 541 securityfs_remove(lst[i]); 542} 543EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); 544MODULE_LICENSE("GPL"); 545