diff mbox series

[v7,2/2] tpm: Map the ACPI provided event log

Message ID 20241227060053.174314-2-jarkko@kernel.org (mailing list archive)
State New
Headers show
Series [v7,1/2] tpm: Map the ACPI provided event log | expand

Commit Message

Jarkko Sakkinen Dec. 27, 2024, 6 a.m. UTC
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.

Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
Tested-by: Andy Liang <andy.liang@hpe.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
v7:
* Fixed up tags.
* I did consider traverse and thus get smaller buffer, and then using
  devm_kmalloc() but looking at e.g. drivers/acpi/apei/einj-core.c
  it is not necessary.
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   | 33 ++++++--------------------
 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(+), 61 deletions(-)

Comments

Ard Biesheuvel Dec. 27, 2024, 8:43 a.m. UTC | #1
On Fri, 27 Dec 2024 at 07:01, Jarkko Sakkinen <jarkko@kernel.org> wrote:
>
> 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.
>
> Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
> Tested-by: Andy Liang <andy.liang@hpe.com>
> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

Where are patch 1/2 and the cover letter?

> ---
> v7:
> * Fixed up tags.
> * I did consider traverse and thus get smaller buffer, and then using
>   devm_kmalloc() but looking at e.g. drivers/acpi/apei/einj-core.c
>   it is not necessary.
> 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   | 33 ++++++--------------------
>  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(+), 61 deletions(-)
>
> diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c
> index 394c8302cefd..a11f78e41e1e 100644
> --- a/drivers/char/tpm/eventlog/acpi.c
> +++ b/drivers/char/tpm/eventlog/acpi.c
> @@ -75,14 +75,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.
>          */
> @@ -140,42 +137,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;
> -
> -       ret = devm_add_action_or_reset(&chip->dev, tpm_bios_log_free, log->bios_event_log);
> -       if (ret) {
> -               log->bios_event_log = NULL;
> -               return ret;
> -       }
> -
> -       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;
>  }
> diff --git a/drivers/char/tpm/eventlog/common.c b/drivers/char/tpm/eventlog/common.c
> index 4c0bbba64ee5..44340ca6e2ac 100644
> --- a/drivers/char/tpm/eventlog/common.c
> +++ b/drivers/char/tpm/eventlog/common.c
> @@ -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 = {
> diff --git a/drivers/char/tpm/eventlog/common.h b/drivers/char/tpm/eventlog/common.h
> index 47ff8136ceb5..b98fd6d9a6e9 100644
> --- a/drivers/char/tpm/eventlog/common.h
> +++ b/drivers/char/tpm/eventlog/common.h
> @@ -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
> diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c
> index 12ee42a31c71..aef6ee39423a 100644
> --- a/drivers/char/tpm/eventlog/tpm1.c
> +++ b/drivers/char/tpm/eventlog/tpm1.c
> @@ -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,
> diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
> index 37a05800980c..6289d8893e46 100644
> --- a/drivers/char/tpm/eventlog/tpm2.c
> +++ b/drivers/char/tpm/eventlog/tpm2.c
> @@ -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;
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 20a40ade8030..f3d12738b93b 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -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)
> --
> 2.47.1
>
Jarkko Sakkinen Dec. 27, 2024, 10:49 a.m. UTC | #2
On Fri Dec 27, 2024 at 10:43 AM EET, Ard Biesheuvel wrote:
> On Fri, 27 Dec 2024 at 07:01, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >
> > 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.
> >
> > Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
> > Tested-by: Andy Liang <andy.liang@hpe.com>
> > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
>
> Where are patch 1/2 and the cover letter?

https://lore.kernel.org/linux-integrity/20241227060053.174314-1-jarkko@kernel.org/T/#mc34835f6d6f946c50a580f895f24b7b1dab85204

You did not request a cover letter, and I did not think it was
really necessary. I can do it for next version on request.

BR, Jarkko
Jarkko Sakkinen Dec. 27, 2024, 10:52 a.m. UTC | #3
On Fri Dec 27, 2024 at 12:49 PM EET, Jarkko Sakkinen wrote:
> On Fri Dec 27, 2024 at 10:43 AM EET, Ard Biesheuvel wrote:
> > On Fri, 27 Dec 2024 at 07:01, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > >
> > > 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.
> > >
> > > Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
> > > Tested-by: Andy Liang <andy.liang@hpe.com>
> > > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
> >
> > Where are patch 1/2 and the cover letter?
>
> https://lore.kernel.org/linux-integrity/20241227060053.174314-1-jarkko@kernel.org/T/#mc34835f6d6f946c50a580f895f24b7b1dab85204
>
> You did not request a cover letter, and I did not think it was
> really necessary. I can do it for next version on request.

Hmm.. right so this is how I generate Cc's:

    tocmd ="`pwd`/scripts/get_maintainer.pl --norolestats --nol"
    cccmd ="`pwd`/scripts/get_maintainer.pl --norolestats --nom"

It clearly did not pick you (sorry about that).  I'll add manual cc to
the next version. And yeah, cover letter is fine, but I did not see any
(practical) use for it as the patches carry change logs.

BR, Jarkko
Jarkko Sakkinen Dec. 27, 2024, 3:15 p.m. UTC | #4
On Fri Dec 27, 2024 at 12:52 PM EET, Jarkko Sakkinen wrote:
> On Fri Dec 27, 2024 at 12:49 PM EET, Jarkko Sakkinen wrote:
> > On Fri Dec 27, 2024 at 10:43 AM EET, Ard Biesheuvel wrote:
> > > On Fri, 27 Dec 2024 at 07:01, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > > >
> > > > 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.
> > > >
> > > > Suggested-by: Matthew Garrett <mjg59@srcf.ucam.org>
> > > > Tested-by: Andy Liang <andy.liang@hpe.com>
> > > > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
> > >
> > > Where are patch 1/2 and the cover letter?
> >
> > https://lore.kernel.org/linux-integrity/20241227060053.174314-1-jarkko@kernel.org/T/#mc34835f6d6f946c50a580f895f24b7b1dab85204
> >
> > You did not request a cover letter, and I did not think it was
> > really necessary. I can do it for next version on request.
>
> Hmm.. right so this is how I generate Cc's:
>
>     tocmd ="`pwd`/scripts/get_maintainer.pl --norolestats --nol"
>     cccmd ="`pwd`/scripts/get_maintainer.pl --norolestats --nom"
>
> It clearly did not pick you (sorry about that).  I'll add manual cc to
> the next version. And yeah, cover letter is fine, but I did not see any
> (practical) use for it as the patches carry change logs.

I'll reduce this to quick fix after reconsidering. We have the mapped
version drafted and backed up in lore. I'll re-send just that with and
CC you. Or actually I'll put suggested-by tag.

BR, Jarkko
diff mbox series

Patch

diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c
index 394c8302cefd..a11f78e41e1e 100644
--- a/drivers/char/tpm/eventlog/acpi.c
+++ b/drivers/char/tpm/eventlog/acpi.c
@@ -75,14 +75,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.
 	 */
@@ -140,42 +137,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;
-
-	ret = devm_add_action_or_reset(&chip->dev, tpm_bios_log_free, log->bios_event_log);
-	if (ret) {
-		log->bios_event_log = NULL;
-		return ret;
-	}
-
-	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;
 }
diff --git a/drivers/char/tpm/eventlog/common.c b/drivers/char/tpm/eventlog/common.c
index 4c0bbba64ee5..44340ca6e2ac 100644
--- a/drivers/char/tpm/eventlog/common.c
+++ b/drivers/char/tpm/eventlog/common.c
@@ -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 = {
diff --git a/drivers/char/tpm/eventlog/common.h b/drivers/char/tpm/eventlog/common.h
index 47ff8136ceb5..b98fd6d9a6e9 100644
--- a/drivers/char/tpm/eventlog/common.h
+++ b/drivers/char/tpm/eventlog/common.h
@@ -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
diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c
index 12ee42a31c71..aef6ee39423a 100644
--- a/drivers/char/tpm/eventlog/tpm1.c
+++ b/drivers/char/tpm/eventlog/tpm1.c
@@ -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,
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
index 37a05800980c..6289d8893e46 100644
--- a/drivers/char/tpm/eventlog/tpm2.c
+++ b/drivers/char/tpm/eventlog/tpm2.c
@@ -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;
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 20a40ade8030..f3d12738b93b 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -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)