aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tpm/tpm-chip.c3
-rw-r--r--drivers/char/tpm/tpm.h11
-rw-r--r--drivers/char/tpm/tpm_acpi.c15
-rw-r--r--drivers/char/tpm/tpm_eventlog.c86
-rw-r--r--drivers/char/tpm/tpm_eventlog.h2
-rw-r--r--drivers/char/tpm/tpm_of.c4
6 files changed, 84 insertions, 37 deletions
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 250a651ebd95..3f27753d96aa 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -127,6 +127,7 @@ static void tpm_dev_release(struct device *dev)
127 idr_remove(&dev_nums_idr, chip->dev_num); 127 idr_remove(&dev_nums_idr, chip->dev_num);
128 mutex_unlock(&idr_lock); 128 mutex_unlock(&idr_lock);
129 129
130 kfree(chip->log.bios_event_log);
130 kfree(chip); 131 kfree(chip);
131} 132}
132 133
@@ -345,7 +346,7 @@ int tpm_chip_register(struct tpm_chip *chip)
345 tpm_sysfs_add_device(chip); 346 tpm_sysfs_add_device(chip);
346 347
347 rc = tpm_bios_log_setup(chip); 348 rc = tpm_bios_log_setup(chip);
348 if (rc) 349 if (rc == -ENODEV)
349 return rc; 350 return rc;
350 351
351 tpm_add_ppi(chip); 352 tpm_add_ppi(chip);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 9d69580a9743..1ae976894257 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -35,6 +35,8 @@
35#include <linux/cdev.h> 35#include <linux/cdev.h>
36#include <linux/highmem.h> 36#include <linux/highmem.h>
37 37
38#include "tpm_eventlog.h"
39
38enum tpm_const { 40enum tpm_const {
39 TPM_MINOR = 224, /* officially assigned */ 41 TPM_MINOR = 224, /* officially assigned */
40 TPM_BUFSIZE = 4096, 42 TPM_BUFSIZE = 4096,
@@ -146,6 +148,11 @@ enum tpm_chip_flags {
146 TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), 148 TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
147}; 149};
148 150
151struct tpm_chip_seqops {
152 struct tpm_chip *chip;
153 const struct seq_operations *seqops;
154};
155
149struct tpm_chip { 156struct tpm_chip {
150 struct device dev; 157 struct device dev;
151 struct cdev cdev; 158 struct cdev cdev;
@@ -157,6 +164,10 @@ struct tpm_chip {
157 struct rw_semaphore ops_sem; 164 struct rw_semaphore ops_sem;
158 const struct tpm_class_ops *ops; 165 const struct tpm_class_ops *ops;
159 166
167 struct tpm_bios_log log;
168 struct tpm_chip_seqops bin_log_seqops;
169 struct tpm_chip_seqops ascii_log_seqops;
170
160 unsigned int flags; 171 unsigned int flags;
161 172
162 int dev_num; /* /dev/tpm# */ 173 int dev_num; /* /dev/tpm# */
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c
index 565a9478cb94..01dfb35a30e4 100644
--- a/drivers/char/tpm/tpm_acpi.c
+++ b/drivers/char/tpm/tpm_acpi.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * Maintained by: <tpmdd-devel@lists.sourceforge.net> 10 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
11 * 11 *
12 * Access to the eventlog extended by the TCG BIOS of PC platform 12 * Access to the event log extended by the TCG BIOS of PC platform
13 * 13 *
14 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -45,13 +45,15 @@ struct acpi_tcpa {
45}; 45};
46 46
47/* read binary bios log */ 47/* read binary bios log */
48int read_log(struct tpm_bios_log *log) 48int read_log(struct tpm_chip *chip)
49{ 49{
50 struct acpi_tcpa *buff; 50 struct acpi_tcpa *buff;
51 acpi_status status; 51 acpi_status status;
52 void __iomem *virt; 52 void __iomem *virt;
53 u64 len, start; 53 u64 len, start;
54 struct tpm_bios_log *log;
54 55
56 log = &chip->log;
55 if (log->bios_event_log != NULL) { 57 if (log->bios_event_log != NULL) {
56 printk(KERN_ERR 58 printk(KERN_ERR
57 "%s: ERROR - Eventlog already initialized\n", 59 "%s: ERROR - Eventlog already initialized\n",
@@ -97,13 +99,18 @@ int read_log(struct tpm_bios_log *log)
97 99
98 virt = acpi_os_map_iomem(start, len); 100 virt = acpi_os_map_iomem(start, len);
99 if (!virt) { 101 if (!virt) {
100 kfree(log->bios_event_log);
101 printk("%s: ERROR - Unable to map memory\n", __func__); 102 printk("%s: ERROR - Unable to map memory\n", __func__);
102 return -EIO; 103 goto err;
103 } 104 }
104 105
105 memcpy_fromio(log->bios_event_log, virt, len); 106 memcpy_fromio(log->bios_event_log, virt, len);
106 107
107 acpi_os_unmap_iomem(virt, len); 108 acpi_os_unmap_iomem(virt, len);
108 return 0; 109 return 0;
110
111err:
112 kfree(log->bios_event_log);
113 log->bios_event_log = NULL;
114 return -EIO;
115
109} 116}
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c
index 0afb0f4e81f0..2c4bc99729e5 100644
--- a/drivers/char/tpm/tpm_eventlog.c
+++ b/drivers/char/tpm/tpm_eventlog.c
@@ -11,7 +11,7 @@
11 * 11 *
12 * Maintained by: <tpmdd-devel@lists.sourceforge.net> 12 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
13 * 13 *
14 * Access to the eventlog created by a system's firmware / BIOS 14 * Access to the event log created by a system's firmware / BIOS
15 * 15 *
16 * This program is free software; you can redistribute it and/or 16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License 17 * modify it under the terms of the GNU General Public License
@@ -73,7 +73,8 @@ static const char* tcpa_pc_event_id_strings[] = {
73static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) 73static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
74{ 74{
75 loff_t i; 75 loff_t i;
76 struct tpm_bios_log *log = m->private; 76 struct tpm_chip *chip = m->private;
77 struct tpm_bios_log *log = &chip->log;
77 void *addr = log->bios_event_log; 78 void *addr = log->bios_event_log;
78 void *limit = log->bios_event_log_end; 79 void *limit = log->bios_event_log_end;
79 struct tcpa_event *event; 80 struct tcpa_event *event;
@@ -120,7 +121,8 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
120 loff_t *pos) 121 loff_t *pos)
121{ 122{
122 struct tcpa_event *event = v; 123 struct tcpa_event *event = v;
123 struct tpm_bios_log *log = m->private; 124 struct tpm_chip *chip = m->private;
125 struct tpm_bios_log *log = &chip->log;
124 void *limit = log->bios_event_log_end; 126 void *limit = log->bios_event_log_end;
125 u32 converted_event_size; 127 u32 converted_event_size;
126 u32 converted_event_type; 128 u32 converted_event_type;
@@ -261,13 +263,10 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
261static int tpm_bios_measurements_release(struct inode *inode, 263static int tpm_bios_measurements_release(struct inode *inode,
262 struct file *file) 264 struct file *file)
263{ 265{
264 struct seq_file *seq = file->private_data; 266 struct seq_file *seq = (struct seq_file *)file->private_data;
265 struct tpm_bios_log *log = seq->private; 267 struct tpm_chip *chip = (struct tpm_chip *)seq->private;
266 268
267 if (log) { 269 put_device(&chip->dev);
268 kfree(log->bios_event_log);
269 kfree(log);
270 }
271 270
272 return seq_release(inode, file); 271 return seq_release(inode, file);
273} 272}
@@ -323,33 +322,30 @@ static int tpm_bios_measurements_open(struct inode *inode,
323 struct file *file) 322 struct file *file)
324{ 323{
325 int err; 324 int err;
326 struct tpm_bios_log *log;
327 struct seq_file *seq; 325 struct seq_file *seq;
328 const struct seq_operations *seqops = 326 struct tpm_chip_seqops *chip_seqops;
329 (const struct seq_operations *)inode->i_private; 327 const struct seq_operations *seqops;
330 328 struct tpm_chip *chip;
331 log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); 329
332 if (!log) 330 inode_lock(inode);
333 return -ENOMEM; 331 if (!inode->i_private) {
334 332 inode_unlock(inode);
335 if ((err = read_log(log))) 333 return -ENODEV;
336 goto out_free; 334 }
335 chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
336 seqops = chip_seqops->seqops;
337 chip = chip_seqops->chip;
338 get_device(&chip->dev);
339 inode_unlock(inode);
337 340
338 /* now register seq file */ 341 /* now register seq file */
339 err = seq_open(file, seqops); 342 err = seq_open(file, seqops);
340 if (!err) { 343 if (!err) {
341 seq = file->private_data; 344 seq = file->private_data;
342 seq->private = log; 345 seq->private = chip;
343 } else {
344 goto out_free;
345 } 346 }
346 347
347out:
348 return err; 348 return err;
349out_free:
350 kfree(log->bios_event_log);
351 kfree(log);
352 goto out;
353} 349}
354 350
355static const struct file_operations tpm_bios_measurements_ops = { 351static const struct file_operations tpm_bios_measurements_ops = {
@@ -363,10 +359,22 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
363{ 359{
364 const char *name = dev_name(&chip->dev); 360 const char *name = dev_name(&chip->dev);
365 unsigned int cnt; 361 unsigned int cnt;
362 int rc = 0;
366 363
367 if (chip->flags & TPM_CHIP_FLAG_TPM2) 364 if (chip->flags & TPM_CHIP_FLAG_TPM2)
368 return 0; 365 return 0;
369 366
367 rc = read_log(chip);
368 /*
369 * read_log failure means event log is not supported except for ENOMEM.
370 */
371 if (rc < 0) {
372 if (rc == -ENOMEM)
373 return -ENODEV;
374 else
375 return rc;
376 }
377
370 cnt = 0; 378 cnt = 0;
371 chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); 379 chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
372 /* NOTE: securityfs_create_dir can return ENODEV if securityfs is 380 /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
@@ -376,19 +384,25 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
376 goto err; 384 goto err;
377 cnt++; 385 cnt++;
378 386
387 chip->bin_log_seqops.chip = chip;
388 chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops;
389
379 chip->bios_dir[cnt] = 390 chip->bios_dir[cnt] =
380 securityfs_create_file("binary_bios_measurements", 391 securityfs_create_file("binary_bios_measurements",
381 0440, chip->bios_dir[0], 392 0440, chip->bios_dir[0],
382 (void *)&tpm_binary_b_measurements_seqops, 393 (void *)&chip->bin_log_seqops,
383 &tpm_bios_measurements_ops); 394 &tpm_bios_measurements_ops);
384 if (IS_ERR(chip->bios_dir[cnt])) 395 if (IS_ERR(chip->bios_dir[cnt]))
385 goto err; 396 goto err;
386 cnt++; 397 cnt++;
387 398
399 chip->ascii_log_seqops.chip = chip;
400 chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops;
401
388 chip->bios_dir[cnt] = 402 chip->bios_dir[cnt] =
389 securityfs_create_file("ascii_bios_measurements", 403 securityfs_create_file("ascii_bios_measurements",
390 0440, chip->bios_dir[0], 404 0440, chip->bios_dir[0],
391 (void *)&tpm_ascii_b_measurements_seqops, 405 (void *)&chip->ascii_log_seqops,
392 &tpm_bios_measurements_ops); 406 &tpm_bios_measurements_ops);
393 if (IS_ERR(chip->bios_dir[cnt])) 407 if (IS_ERR(chip->bios_dir[cnt]))
394 goto err; 408 goto err;
@@ -405,7 +419,19 @@ err:
405void tpm_bios_log_teardown(struct tpm_chip *chip) 419void tpm_bios_log_teardown(struct tpm_chip *chip)
406{ 420{
407 int i; 421 int i;
422 struct inode *inode;
408 423
409 for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) 424 /* securityfs_remove currently doesn't take care of handling sync
425 * between removal and opening of pseudo files. To handle this, a
426 * workaround is added by making i_private = NULL here during removal
427 * and to check it during open(), both within inode_lock()/unlock().
428 * This design ensures that open() either safely gets kref or fails.
429 */
430 for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
431 inode = d_inode(chip->bios_dir[i]);
432 inode_lock(inode);
433 inode->i_private = NULL;
434 inode_unlock(inode);
410 securityfs_remove(chip->bios_dir[i]); 435 securityfs_remove(chip->bios_dir[i]);
436 }
411} 437}
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h
index fd3357e3a322..6df2f8e79a8e 100644
--- a/drivers/char/tpm/tpm_eventlog.h
+++ b/drivers/char/tpm/tpm_eventlog.h
@@ -73,7 +73,7 @@ enum tcpa_pc_event_ids {
73 HOST_TABLE_OF_DEVICES, 73 HOST_TABLE_OF_DEVICES,
74}; 74};
75 75
76int read_log(struct tpm_bios_log *log); 76int read_log(struct tpm_chip *chip);
77 77
78#if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ 78#if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \
79 defined(CONFIG_ACPI) 79 defined(CONFIG_ACPI)
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
index 570f30c5c5f4..68d891ab55db 100644
--- a/drivers/char/tpm/tpm_of.c
+++ b/drivers/char/tpm/tpm_of.c
@@ -20,12 +20,14 @@
20#include "tpm.h" 20#include "tpm.h"
21#include "tpm_eventlog.h" 21#include "tpm_eventlog.h"
22 22
23int read_log(struct tpm_bios_log *log) 23int read_log(struct tpm_chip *chip)
24{ 24{
25 struct device_node *np; 25 struct device_node *np;
26 const u32 *sizep; 26 const u32 *sizep;
27 const u64 *basep; 27 const u64 *basep;
28 struct tpm_bios_log *log;
28 29
30 log = &chip->log;
29 if (log->bios_event_log != NULL) { 31 if (log->bios_event_log != NULL) {
30 pr_err("%s: ERROR - Eventlog already initialized\n", __func__); 32 pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
31 return -EFAULT; 33 return -EFAULT;