Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19-rc2 546 lines 12 kB view raw
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_firmware_table(ACPI_TCPA_SIG, 1, 376 ACPI_LOGICAL_ADDRESSING, 377 (struct acpi_table_header **) 378 &buff); 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 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) { 398 printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); 399 return -EIO; 400 } 401 402 /* malloc EventLog space */ 403 log->bios_event_log = kmalloc(len, GFP_KERNEL); 404 if (!log->bios_event_log) { 405 printk("%s: ERROR - Not enough Memory for BIOS measurements\n", 406 __func__); 407 return -ENOMEM; 408 } 409 410 log->bios_event_log_end = log->bios_event_log + len; 411 412 acpi_os_map_memory(start, len, (void *) &virt); 413 414 memcpy(log->bios_event_log, virt, len); 415 416 acpi_os_unmap_memory(virt, len); 417 return 0; 418} 419 420static int tpm_ascii_bios_measurements_open(struct inode *inode, 421 struct file *file) 422{ 423 int err; 424 struct tpm_bios_log *log; 425 struct seq_file *seq; 426 427 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); 428 if (!log) 429 return -ENOMEM; 430 431 if ((err = read_log(log))) 432 return err; 433 434 /* now register seq file */ 435 err = seq_open(file, &tpm_ascii_b_measurments_seqops); 436 if (!err) { 437 seq = file->private_data; 438 seq->private = log; 439 } else { 440 kfree(log->bios_event_log); 441 kfree(log); 442 } 443 return err; 444} 445 446struct file_operations tpm_ascii_bios_measurements_ops = { 447 .open = tpm_ascii_bios_measurements_open, 448 .read = seq_read, 449 .llseek = seq_lseek, 450 .release = tpm_bios_measurements_release, 451}; 452 453static int tpm_binary_bios_measurements_open(struct inode *inode, 454 struct file *file) 455{ 456 int err; 457 struct tpm_bios_log *log; 458 struct seq_file *seq; 459 460 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); 461 if (!log) 462 return -ENOMEM; 463 464 if ((err = read_log(log))) 465 return err; 466 467 /* now register seq file */ 468 err = seq_open(file, &tpm_binary_b_measurments_seqops); 469 if (!err) { 470 seq = file->private_data; 471 seq->private = log; 472 } else { 473 kfree(log->bios_event_log); 474 kfree(log); 475 } 476 return err; 477} 478 479struct file_operations tpm_binary_bios_measurements_ops = { 480 .open = tpm_binary_bios_measurements_open, 481 .read = seq_read, 482 .llseek = seq_lseek, 483 .release = tpm_bios_measurements_release, 484}; 485 486static int is_bad(void *p) 487{ 488 if (!p) 489 return 1; 490 if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV)) 491 return 1; 492 return 0; 493} 494 495struct dentry **tpm_bios_log_setup(char *name) 496{ 497 struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; 498 499 tpm_dir = securityfs_create_dir(name, NULL); 500 if (is_bad(tpm_dir)) 501 goto out; 502 503 bin_file = 504 securityfs_create_file("binary_bios_measurements", 505 S_IRUSR | S_IRGRP, tpm_dir, NULL, 506 &tpm_binary_bios_measurements_ops); 507 if (is_bad(bin_file)) 508 goto out_tpm; 509 510 ascii_file = 511 securityfs_create_file("ascii_bios_measurements", 512 S_IRUSR | S_IRGRP, tpm_dir, NULL, 513 &tpm_ascii_bios_measurements_ops); 514 if (is_bad(ascii_file)) 515 goto out_bin; 516 517 ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); 518 if (!ret) 519 goto out_ascii; 520 521 ret[0] = ascii_file; 522 ret[1] = bin_file; 523 ret[2] = tpm_dir; 524 525 return ret; 526 527out_ascii: 528 securityfs_remove(ascii_file); 529out_bin: 530 securityfs_remove(bin_file); 531out_tpm: 532 securityfs_remove(tpm_dir); 533out: 534 return NULL; 535} 536EXPORT_SYMBOL_GPL(tpm_bios_log_setup); 537 538void tpm_bios_log_teardown(struct dentry **lst) 539{ 540 int i; 541 542 for (i = 0; i < 3; i++) 543 securityfs_remove(lst[i]); 544} 545EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); 546MODULE_LICENSE("GPL");