tpm: Map the ACPI provided event log
Subsystems (3)
Jarkko Sakkinen
maintainerPATCH v6 1/2 tpm: Map the ACPI provided event log
The following failure was reported:
[ 10.693310][ T1] tpm_tis STM0925:00: 2.0 TPM (device-id 0x3, rev-id 0) [ 10.848132][ T1] ------------[ cut here ]------------ [ 10.853559][ T1] WARNING: CPU: 59 PID: 1 at mm/page_alloc.c:4727 __alloc_pages_noprof+0x2ca/0x330 [ 10.862827][ T1] Modules linked in: [ 10.866671][ T1] CPU: 59 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.0-lp155.2.g52785e2-default #1 openSUSE Tumbleweed (unreleased) 588cd98293a7c9eba9013378d807364c088c9375 [ 10.882741][ T1] Hardware name: HPE ProLiant DL320 Gen12/ProLiant DL320 Gen12, BIOS 1.20 10/28/2024 [ 10.892170][ T1] RIP: 0010:__alloc_pages_noprof+0x2ca/0x330 [ 10.898103][ T1] Code: 24 08 e9 4a fe ff ff e8 34 36 fa ff e9 88 fe ff ff 83 fe 0a 0f 86 b3 fd ff ff 80 3d 01 e7 ce 01 00 75 09 c6 05 f8 e6 ce 01 01 <0f> 0b 45 31 ff e9 e5 fe ff ff f7 c2 00 00 08 00 75 42 89 d9 80 e1 [ 10.917750][ T1] RSP: 0000:ffffb7cf40077980 EFLAGS: 00010246 [ 10.923777][ T1] RAX: 0000000000000000 RBX: 0000000000040cc0 RCX: 0000000000000000 [ 10.931727][ T1] RDX: 0000000000000000 RSI: 000000000000000c RDI: 0000000000040cc0
Above shows that ACPI pointed a 16 MiB buffer for the log events because RSI maps to the 'order' parameter of __alloc_pages_noprof(). Address the bug with kvmalloc() and devres_add().
---
v6:
* A new patch.
--- drivers/char/tpm/eventlog/acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/char/tpm/eventlog/acpi.c +3 -1
@@ -136,10 +136,12 @@ int tpm_read_log_acpi(struct tpm_chip *chip) }/* malloc EventLog space */ - log->bios_event_log =devm_kmalloc (&chip->dev, len,GFP_KERNEL ); + log->bios_event_log =kvmalloc (len,GFP_KERNEL );if (!log->bios_event_log)return -ENOMEM ; +devres_add (&chip->dev, log->bios_event_log); + log->bios_event_log_end = log->bios_event_log + len; virt =acpi_os_map_iomem (start, len);
Signature · 1 line
2.47.1
Jarkko Sakkinen
maintainerPATCH v6 2/2 tpm: Map the ACPI provided event log
The following failure was reported:
[ 10.693310][ T1] tpm_tis STM0925:00: 2.0 TPM (device-id 0x3, rev-id 0) [ 10.848132][ T1] ------------[ cut here ]------------ [ 10.853559][ T1] WARNING: CPU: 59 PID: 1 at mm/page_alloc.c:4727 __alloc_pages_noprof+0x2ca/0x330 [ 10.862827][ T1] Modules linked in: [ 10.866671][ T1] CPU: 59 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.0-lp155.2.g52785e2-default #1 openSUSE Tumbleweed (unreleased) 588cd98293a7c9eba9013378d807364c088c9375 [ 10.882741][ T1] Hardware name: HPE ProLiant DL320 Gen12/ProLiant DL320 Gen12, BIOS 1.20 10/28/2024 [ 10.892170][ T1] RIP: 0010:__alloc_pages_noprof+0x2ca/0x330 [ 10.898103][ T1] Code: 24 08 e9 4a fe ff ff e8 34 36 fa ff e9 88 fe ff ff 83 fe 0a 0f 86 b3 fd ff ff 80 3d 01 e7 ce 01 00 75 09 c6 05 f8 e6 ce 01 01 <0f> 0b 45 31 ff e9 e5 fe ff ff f7 c2 00 00 08 00 75 42 89 d9 80 e1 [ 10.917750][ T1] RSP: 0000:ffffb7cf40077980 EFLAGS: 00010246 [ 10.923777][ T1] RAX: 0000000000000000 RBX: 0000000000040cc0 RCX: 0000000000000000 [ 10.931727][ T1] RDX: 0000000000000000 RSI: 000000000000000c RDI: 0000000000040cc0
Above shows that ACPI pointed a 16 MiB buffer for the log events because RSI maps to the 'order' parameter of __alloc_pages_noprof(). Address the bug by mapping the region when needed instead of copying.
Earlier fix does address the warning but wastes 16 MiB of memory. This finalizes the fix.
---
v6:
* Updated commit message.
v5:
* Spotted this right after sending: remove extra acpi_os_unmap_iomem() call.
v4:
* Added tested-by from Andy Liang.
v3:
* Flag mapping code in tpm{1,2}.c with CONFIG_ACPI (nios2 compilation fix).
v2:
* There was some extra cruft (irrelevant diff), which is now wiped away.
* Added missing tags (fixes, stable).
--- drivers/char/tpm/eventlog/acpi.c | 29 ++++++----------------- drivers/char/tpm/eventlog/common.c | 25 +++++++++++++------- drivers/char/tpm/eventlog/common.h | 28 ++++++++++++++++++++++ drivers/char/tpm/eventlog/tpm1.c | 30 ++++++++++++++--------- drivers/char/tpm/eventlog/tpm2.c | 38 +++++++++++++++++------------- include/linux/tpm.h | 1 + 6 files changed, 94 insertions(+), 57 deletions(-)
drivers/char/tpm/eventlog/acpi.c +7 -22
@@ -70,14 +70,11 @@ int tpm_read_log_acpi(struct tpm_chip *chip)acpi_status status;void __iomem *virt;u64 len, start; -struct tpm_bios_log *log;struct acpi_table_tpm2 *tbl;struct acpi_tpm2_phy *tpm2_phy;int format;int ret; - log = &chip->log; -/* Unfortuntely ACPI does not associate the event log with a specific * TPM, like PPI. Thus all ACPI TPMs will read the same log. */
@@ -135,38 +132,26 @@ int tpm_read_log_acpi(struct tpm_chip *chip)return -EIO ; } -/* malloc EventLog space */ - log->bios_event_log =kvmalloc (len,GFP_KERNEL ); -if (!log->bios_event_log) -return -ENOMEM ; - -devres_add (&chip->dev, log->bios_event_log); - - log->bios_event_log_end = log->bios_event_log + len; - virt =acpi_os_map_iomem (start, len);if (!virt) {dev_warn (&chip->dev,"%s: Failed to map ACPI memory\n" , __func__);/* try EFI log next */ - ret = -ENODEV ; - goto err; +return -ENODEV ; } -memcpy_fromio (log->bios_event_log, virt, len); - -acpi_os_unmap_iomem (virt, len); - -if (chip->flags &TPM_CHIP_FLAG_TPM2 && - !tpm_is_tpm2_log (log->bios_event_log, len)) { +if (chip->flags &TPM_CHIP_FLAG_TPM2 && !tpm_is_tpm2_log (virt, len)) {/* try EFI log next */ ret = -ENODEV ; goto err; } +acpi_os_unmap_iomem (virt, len); + chip->flags |=TPM_CHIP_FLAG_ACPI_LOG ; + chip->log.bios_event_log = (void *)start; + chip->log.bios_event_log_end = (void *)start + len;return format; err: -devm_kfree (&chip->dev, log->bios_event_log); - log->bios_event_log =NULL ; +acpi_os_unmap_iomem (virt, len);return ret; }
drivers/char/tpm/eventlog/common.c +17 -8
@@ -27,6 +27,7 @@ static int tpm_bios_measurements_open(struct inode *inode, {int err;struct seq_file *seq; +struct tpm_measurements *priv;struct tpm_chip_seqops *chip_seqops;const struct seq_operations *seqops;struct tpm_chip *chip;
@@ -42,13 +43,18 @@ static int tpm_bios_measurements_open(struct inode *inode,get_device (&chip->dev);inode_unlock (inode); -/* now register seq file */ + priv =kzalloc (sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + priv->chip = chip; + err =seq_open (file, seqops); -if (!err) { - seq = file->private_data; - seq->private = chip; - }else { +if (err) { +kfree (priv);put_device (&chip->dev); + }else { + seq = file->private_data; + seq->private = priv; }return err;
@@ -58,11 +64,14 @@ static int tpm_bios_measurements_release(struct inode *inode, struct file *file) {struct seq_file *seq = file->private_data; -struct tpm_chip *chip = seq->private; +struct tpm_measurements *priv = seq->private; +int ret; -put_device (&chip->dev); +put_device (&priv->chip->dev); + ret =seq_release (inode, file); +kfree (priv); -return seq_release (inode, file); +return ret; }static const struct file_operations tpm_bios_measurements_ops = {
drivers/char/tpm/eventlog/common.h +28 -0
@@ -1,12 +1,40 @@#ifndef __TPM_EVENTLOG_COMMON_H__#define __TPM_EVENTLOG_COMMON_H__ +#include <linux/acpi.h> #include "../tpm.h" extern const struct seq_operations tpm1_ascii_b_measurements_seqops;extern const struct seq_operations tpm1_binary_b_measurements_seqops;extern const struct seq_operations tpm2_binary_b_measurements_seqops; +struct tpm_measurements { +struct tpm_chip *chip; +void *start; +void *end; +}; + +static inline bool tpm_measurements_map (struct tpm_measurements *measurements) +{ +struct tpm_chip *chip = measurements->chip; +struct tpm_bios_log *log = &chip->log; +size_t size; + + size = log->bios_event_log_end - log->bios_event_log; + measurements->start = log->bios_event_log; + +#ifdef CONFIG_ACPI +if (chip->flags &TPM_CHIP_FLAG_ACPI_LOG ) + measurements->start =acpi_os_map_iomem ((unsigned long )log->bios_event_log, size); +#endif + +if (!measurements->start) +return false; + + measurements->end = measurements->start + size; +return true; +} +#if defined(CONFIG_ACPI )int tpm_read_log_acpi (struct tpm_chip *chip);#else
drivers/char/tpm/eventlog/tpm1.c +19 -11
@@ -70,20 +70,23 @@ static const char* tcpa_pc_event_id_strings[] = {static void *tpm1_bios_measurements_start (struct seq_file *m,loff_t *pos) {loff_t i =0 ; -struct tpm_chip *chip = m->private; -struct tpm_bios_log *log = &chip->log; -void *addr = log->bios_event_log; -void *limit = log->bios_event_log_end; +struct tpm_measurements *priv = m->private;struct tcpa_event *event;u32 converted_event_size;u32 converted_event_type; +void *addr; + +if (!tpm_measurements_map (priv)) +return NULL ; + + addr = priv->start;/* read over *pos measurements */ do { event = addr; /* check if current entry is valid */ - if (addr + sizeof(struct tcpa_event) > limit) + if (addr + sizeof(struct tcpa_event) > priv->end) return NULL; converted_event_size =
@@ -93,7 +96,7 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)if (((converted_event_type ==0 ) && (converted_event_size ==0 )) || ((addr +sizeof (struct tcpa_event ) + converted_event_size) - > limit)) + > priv->end))return NULL ;if (i++ == *pos)
@@ -109,9 +112,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, loff_t *pos) {struct tcpa_event *event = v; -struct tpm_chip *chip = m->private; -struct tpm_bios_log *log = &chip->log; -void *limit = log->bios_event_log_end; +struct tpm_measurements *priv = m->private;u32 converted_event_size;u32 converted_event_type;
@@ -121,7 +122,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, v +=sizeof (struct tcpa_event ) + converted_event_size;/* now check if current entry is valid */ -if ((v +sizeof (struct tcpa_event )) > limit) +if ((v +sizeof (struct tcpa_event )) > priv->end)return NULL ; event = v;
@@ -130,7 +131,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, converted_event_type =do_endian_conversion (event->event_type);if (((converted_event_type ==0 ) && (converted_event_size ==0 )) || - ((v +sizeof (struct tcpa_event ) + converted_event_size) > limit)) + ((v +sizeof (struct tcpa_event ) + converted_event_size) > priv->end))return NULL ;return v;
@@ -138,6 +139,13 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,static void tpm1_bios_measurements_stop (struct seq_file *m,void *v) { +#ifdef CONFIG_ACPI +struct tpm_measurements *priv = m->private; +struct tpm_chip *chip = priv->chip; + +if (chip->flags &TPM_CHIP_FLAG_ACPI_LOG ) +acpi_os_unmap_iomem (priv->start, priv->end - priv->start); +#endif } static int get_event_name(char *dest, struct tcpa_event *event,
drivers/char/tpm/eventlog/tpm2.c +22 -16
@@ -41,20 +41,22 @@ static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,static void *tpm2_bios_measurements_start (struct seq_file *m,loff_t *pos) { -struct tpm_chip *chip = m->private; -struct tpm_bios_log *log = &chip->log; -void *addr = log->bios_event_log; -void *limit = log->bios_event_log_end; +struct tpm_measurements *priv = m->private;struct tcg_pcr_event *event_header;struct tcg_pcr_event2_head *event;size_t size; +void *addr;int i; +if (!tpm_measurements_map (priv)) +return NULL ; + + addr = priv->start; event_header = addr; size =struct_size (event_header, event, event_header->event_size);if (*pos ==0 ) { -if (addr + size < limit) { +if (addr + size < priv->end) {if ((event_header->event_type ==0 ) && (event_header->event_size ==0 ))return NULL ;
@@ -66,7 +68,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) addr += size; event = addr; size =calc_tpm2_event_size (event, event_header); -if ((addr + size >= limit) || (size ==0 )) +if ((addr + size >= priv->end) || !size)return NULL ; }
@@ -74,7 +76,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) event = addr; size =calc_tpm2_event_size (event, event_header); -if ((addr + size >= limit) || (size ==0 )) +if ((addr + size >= priv->end) || !size)return NULL ; addr += size; }
@@ -87,14 +89,12 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, {struct tcg_pcr_event *event_header;struct tcg_pcr_event2_head *event; -struct tpm_chip *chip = m->private; -struct tpm_bios_log *log = &chip->log; -void *limit = log->bios_event_log_end; +struct tpm_measurements *priv = m->private;size_t event_size;void *marker; (*pos)++; - event_header = log->bios_event_log; + event_header = priv->start;if (v ==SEQ_START_TOKEN ) { event_size = struct_size(event_header, event,
@@ -109,13 +109,13 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, } marker = marker + event_size; -if (marker >= limit) +if (marker >= priv->end)return NULL ; v = marker; event = v; event_size =calc_tpm2_event_size (event, event_header); -if (((v + event_size) >= limit) || (event_size ==0 )) +if (((v + event_size) >= priv->end) || !event_size)return NULL ;return v;
@@ -123,13 +123,19 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,static void tpm2_bios_measurements_stop (struct seq_file *m,void *v) { +#ifdef CONFIG_ACPI +struct tpm_measurements *priv = m->private; +struct tpm_chip *chip = priv->chip; + +if (chip->flags &TPM_CHIP_FLAG_ACPI_LOG ) +acpi_os_unmap_iomem (priv->start, priv->end - priv->start); +#endif }static int tpm2_binary_bios_measurements_show (struct seq_file *m,void *v) { -struct tpm_chip *chip = m->private; -struct tpm_bios_log *log = &chip->log; -struct tcg_pcr_event *event_header = log->bios_event_log; +struct tpm_measurements *priv = m->private; +struct tcg_pcr_event *event_header = priv->start;struct tcg_pcr_event2_head *event = v;void *temp_ptr;size_t size;
include/linux/tpm.h +1 -0
@@ -348,6 +348,7 @@ enum tpm_chip_flags {TPM_CHIP_FLAG_SUSPENDED =BIT (8 ),TPM_CHIP_FLAG_HWRNG_DISABLED =BIT (9 ),TPM_CHIP_FLAG_DISABLE =BIT (10 ), + TPM_CHIP_FLAG_ACPI_LOG = BIT(11), };#define to_tpm_chip (d) container_of(d, struct tpm_chip, dev)
Signature · 1 line
2.47.1
Jarkko Sakkinen
maintainerQuoted 18 lines · Jarkko Sakkinen
The following failure was reported:
[ 10.693310][ T1] tpm_tis STM0925:00: 2.0 TPM (device-id 0x3, rev-id 0) [ 10.848132][ T1] ------------[ cut here ]------------ [ 10.853559][ T1] WARNING: CPU: 59 PID: 1 at mm/page_alloc.c:4727 __alloc_pages_noprof+0x2ca/0x330 [ 10.862827][ T1] Modules linked in: [ 10.866671][ T1] CPU: 59 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.0-lp155.2.g52785e2-default #1 openSUSE Tumbleweed (unreleased) 588cd98293a7c9eba9013378d807364c088c9375 [ 10.882741][ T1] Hardware name: HPE ProLiant DL320 Gen12/ProLiant DL320 Gen12, BIOS 1.20 10/28/2024 [ 10.892170][ T1] RIP: 0010:__alloc_pages_noprof+0x2ca/0x330 [ 10.898103][ T1] Code: 24 08 e9 4a fe ff ff e8 34 36 fa ff e9 88 fe ff ff 83 fe 0a 0f 86 b3 fd ff ff 80 3d 01 e7 ce 01 00 75 09 c6 05 f8 e6 ce 01 01 <0f> 0b 45 31 ff e9 e5 fe ff ff f7 c2 00 00 08 00 75 42 89 d9 80 e1 [ 10.917750][ T1] RSP: 0000:ffffb7cf40077980 EFLAGS: 00010246 [ 10.923777][ T1] RAX: 0000000000000000 RBX: 0000000000040cc0 RCX: 0000000000000000 [ 10.931727][ T1] RDX: 0000000000000000 RSI: 000000000000000c RDI: 0000000000040cc0Above shows that ACPI pointed a 16 MiB buffer for the log events because RSI maps to the 'order' parameter of
__alloc_pages_noprof(). Address the bug withkvmalloc()anddevres_add().
Quoted 5 lines
Cc [email protected] # v2.6.16+Fixes 55a82ab3181b ("[PATCH] tpm: add bios measurement log")Reported-by Andy Liang <[email protected]>Suggested-by Matthew Garrett <[email protected]>
Oops, needs to be dropped from this.
Quoted 13 lines
Signed-off-by Jarkko Sakkinen <[email protected]>---
v6:
* A new patch.--- drivers/char/tpm/eventlog/acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)drivers/char/tpm/eventlog/acpi.c +0
-0
drivers/char/tpm/eventlog/acpi.c int tpm_read_log_acpi(struct tpm_chip *chip) · line 144
Quoted 10 lines
drivers/char/tpm/eventlog/acpi.c +3
-1@@ -136,10 +136,12 @@ int tpm_read_log_acpi(struct tpm_chip *chip) }/* malloc EventLog space */ - log->bios_event_log =devm_kmalloc (&chip->dev, len,GFP_KERNEL ); + log->bios_event_log =kvmalloc (len,GFP_KERNEL );if (!log->bios_event_log)return -ENOMEM ; +devres_add (&chip->dev, log->bios_event_log); +
We either need to git revert 441b7152729f ("tpm: Use managed allocation for bios event log") OR alternatively use devm_add_action() creating a fix that wastes 16 MiB of memory and obfuscates flows more than needed.
I don't necessarily get how come this is "less intrusive"...
BR, Jarkko
Jarkko Sakkinen
maintainerQuoted 48 lines · Jarkko Sakkinen
Quoted 18 lines · Jarkko Sakkinen
The following failure was reported:
[ 10.693310][ T1] tpm_tis STM0925:00: 2.0 TPM (device-id 0x3, rev-id 0) [ 10.848132][ T1] ------------[ cut here ]------------ [ 10.853559][ T1] WARNING: CPU: 59 PID: 1 at mm/page_alloc.c:4727 __alloc_pages_noprof+0x2ca/0x330 [ 10.862827][ T1] Modules linked in: [ 10.866671][ T1] CPU: 59 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.0-lp155.2.g52785e2-default #1 openSUSE Tumbleweed (unreleased) 588cd98293a7c9eba9013378d807364c088c9375 [ 10.882741][ T1] Hardware name: HPE ProLiant DL320 Gen12/ProLiant DL320 Gen12, BIOS 1.20 10/28/2024 [ 10.892170][ T1] RIP: 0010:__alloc_pages_noprof+0x2ca/0x330 [ 10.898103][ T1] Code: 24 08 e9 4a fe ff ff e8 34 36 fa ff e9 88 fe ff ff 83 fe 0a 0f 86 b3 fd ff ff 80 3d 01 e7 ce 01 00 75 09 c6 05 f8 e6 ce 01 01 <0f> 0b 45 31 ff e9 e5 fe ff ff f7 c2 00 00 08 00 75 42 89 d9 80 e1 [ 10.917750][ T1] RSP: 0000:ffffb7cf40077980 EFLAGS: 00010246 [ 10.923777][ T1] RAX: 0000000000000000 RBX: 0000000000040cc0 RCX: 0000000000000000 [ 10.931727][ T1] RDX: 0000000000000000 RSI: 000000000000000c RDI: 0000000000040cc0Above shows that ACPI pointed a 16 MiB buffer for the log events because RSI maps to the 'order' parameter of
__alloc_pages_noprof(). Address the bug withkvmalloc()anddevres_add().Quoted 5 lines
Cc [email protected] # v2.6.16+Fixes 55a82ab3181b ("[PATCH] tpm: add bios measurement log")Reported-by Andy Liang <[email protected]>Suggested-by Matthew Garrett <[email protected]>Oops, needs to be dropped from this.
Quoted 21 lines
Signed-off-by Jarkko Sakkinen <[email protected]>---
v6:
* A new patch.--- drivers/char/tpm/eventlog/acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)drivers/char/tpm/eventlog/acpi.c +1
-1@@ -136,10 +136,12 @@ int tpm_read_log_acpi(struct tpm_chip *chip) }/* malloc EventLog space */ - log->bios_event_log =devm_kmalloc (&chip->dev, len,GFP_KERNEL ); + log->bios_event_log =kvmalloc (len,GFP_KERNEL );if (!log->bios_event_log)return -ENOMEM ;
Quoted 8 lines
drivers/char/tpm/eventlog/acpi.c int tpm_read_log_acpi(struct tpm_chip *chip) · line 144
Quoted 2 lines
drivers/char/tpm/eventlog/acpi.c +2
-0+devres_add (&chip->dev, log->bios_event_log); +We either need to git revert
441b7152729f("tpm: Use managed allocation for bios event log") OR alternatively usedevm_add_action()creating a fix that wastes 16 MiB of memory and obfuscates flows more than needed.I don't necessarily get how come this is "less intrusive"...
Right, so I guess it's not actually very complicated:
ret = devm_add_action_or_reset(&chip->dev, kvfree, &log->bios_event_log)
if (ret) {
log->bios_event_log = NULL;
return ret;
}Had not used this API since we used it in tpmm_chip_alloc(). I'll tweak the patch accordingly...
And since 2/2 becomes a feature patch I'll refine it to do a traverse of the log so we know the actual size of the populated contents and then move back on using devm_kmalloc() in that patch (i.e. it will render out also the fix that the first patch makes).
Not too bad, I can live this.
BR, Jarkko