tpm: Fix handling of missing event log
authorJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Sat, 19 Nov 2016 18:18:28 +0000 (11:18 -0700)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Sun, 27 Nov 2016 23:31:32 +0000 (01:31 +0200)
The event log is an optional firmware feature, if the firmware
does not support it then the securityfs files should not be created
and no other notification given.

- Uniformly return -ENODEV from the tpm_bios_log_setup cone if
  no event log is detected.
- Check in ACPI if this node was discovered via ACPI.
- Improve the check in OF to make sure there is a parent and to
  fail detection if the two log properties are not declared
- Pass through all other error codes instead of filtering just some

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm_acpi.c
drivers/char/tpm/tpm_eventlog.c
drivers/char/tpm/tpm_of.c

index 3f27753..7a48691 100644 (file)
@@ -346,7 +346,7 @@ int tpm_chip_register(struct tpm_chip *chip)
        tpm_sysfs_add_device(chip);
 
        rc = tpm_bios_log_setup(chip);
-       if (rc == -ENODEV)
+       if (rc != 0 && rc != -ENODEV)
                return rc;
 
        tpm_add_ppi(chip);
index 0cb43ef..b7718c9 100644 (file)
@@ -56,12 +56,18 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
 
        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.
+        */
+       if (!chip->acpi_dev_handle)
+               return -ENODEV;
+
        /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
        status = acpi_get_table(ACPI_SIG_TCPA, 1,
                                (struct acpi_table_header **)&buff);
 
        if (ACPI_FAILURE(status))
-               return -EIO;
+               return -ENODEV;
 
        switch(buff->platform_class) {
        case BIOS_SERVER:
index 34f0921..c73f88c 100644 (file)
@@ -368,14 +368,21 @@ static int tpm_read_log(struct tpm_chip *chip)
        }
 
        rc = tpm_read_log_acpi(chip);
-       if ((rc == 0) || (rc == -ENOMEM))
+       if (rc != -ENODEV)
                return rc;
 
-       rc = tpm_read_log_of(chip);
-
-       return rc;
+       return tpm_read_log_of(chip);
 }
 
+/*
+ * tpm_bios_log_setup() - Read the event log from the firmware
+ * @chip: TPM chip to use.
+ *
+ * If an event log is found then the securityfs files are setup to
+ * export it to userspace, otherwise nothing is done.
+ *
+ * Returns -ENODEV if the firmware has no event log.
+ */
 int tpm_bios_log_setup(struct tpm_chip *chip)
 {
        const char *name = dev_name(&chip->dev);
@@ -386,15 +393,8 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
                return 0;
 
        rc = tpm_read_log(chip);
-       /*
-        * read_log failure means event log is not supported except for ENOMEM.
-        */
-       if (rc < 0) {
-               if (rc == -ENOMEM)
-                       return -ENODEV;
-               else
-                       return rc;
-       }
+       if (rc)
+               return rc;
 
        cnt = 0;
        chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
index 36df9df..7dee42d 100644 (file)
@@ -29,13 +29,16 @@ int tpm_read_log_of(struct tpm_chip *chip)
        struct tpm_bios_log *log;
 
        log = &chip->log;
-       if (chip->dev.parent->of_node)
+       if (chip->dev.parent && chip->dev.parent->of_node)
                np = chip->dev.parent->of_node;
        else
                return -ENODEV;
 
        sizep = of_get_property(np, "linux,sml-size", NULL);
-       if (sizep == NULL)
+       basep = of_get_property(np, "linux,sml-base", NULL);
+       if (sizep == NULL && basep == NULL)
+               return -ENODEV;
+       if (sizep == NULL || basep == NULL)
                return -EIO;
 
        if (*sizep == 0) {
@@ -43,10 +46,6 @@ int tpm_read_log_of(struct tpm_chip *chip)
                return -EIO;
        }
 
-       basep = of_get_property(np, "linux,sml-base", NULL);
-       if (basep == NULL)
-               return -EIO;
-
        log->bios_event_log = kmalloc(*sizep, GFP_KERNEL);
        if (!log->bios_event_log)
                return -ENOMEM;