diff options
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 11 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_acpi.c | 15 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog.c | 86 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog.h | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_of.c | 4 |
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 | |||
38 | enum tpm_const { | 40 | enum 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 | ||
151 | struct tpm_chip_seqops { | ||
152 | struct tpm_chip *chip; | ||
153 | const struct seq_operations *seqops; | ||
154 | }; | ||
155 | |||
149 | struct tpm_chip { | 156 | struct 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 */ |
48 | int read_log(struct tpm_bios_log *log) | 48 | int 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 | |||
111 | err: | ||
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[] = { | |||
73 | static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) | 73 | static 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) | |||
261 | static int tpm_bios_measurements_release(struct inode *inode, | 263 | static 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 | ||
347 | out: | ||
348 | return err; | 348 | return err; |
349 | out_free: | ||
350 | kfree(log->bios_event_log); | ||
351 | kfree(log); | ||
352 | goto out; | ||
353 | } | 349 | } |
354 | 350 | ||
355 | static const struct file_operations tpm_bios_measurements_ops = { | 351 | static 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: | |||
405 | void tpm_bios_log_teardown(struct tpm_chip *chip) | 419 | void 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 | ||
76 | int read_log(struct tpm_bios_log *log); | 76 | int 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 | ||
23 | int read_log(struct tpm_bios_log *log) | 23 | int 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; |