From: Yeoreum Yun <yeoreum....@arm.com>

[ Upstream commit 746d9e9f62a6e8ba0eba2b83fc61cfe7fa8797ce ]

To generate the boot_aggregate log in the IMA subsystem using TPM PCR
values, the TPM driver must be built as built-in and must be probed
before the IMA subsystem is initialized.

However, when the TPM device operates over the FF-A protocol using the
CRB interface, probing fails and returns -EPROBE_DEFER if the
tpm_crb_ffa device — an FF-A device that provides the communication
interface to the tpm_crb driver — has not yet been probed.

This issue occurs because both crb_acpi_driver_init() and
tpm_crb_ffa_driver_init() are registered with device_initcall.  As a
result, crb_acpi_driver_init() may be invoked before
tpm_crb_ffa_driver_init(), which is responsible for probing the
tpm_crb_ffa device.

When this happens, IMA fails to detect the TPM device and logs the
following message:

  | ima: No TPM chip found, activating TPM-bypass!

Consequently, it cannot generate the boot_aggregate log with the PCR
values provided by the TPM.

To resolve this issue, the tpm_crb_ffa_init() function explicitly
attempts to probe the tpm_crb_ffa by register tpm_crb_ffa driver so that
when tpm_crb_ffa device is created before tpm_crb_ffa_init(), probe the
tpm_crb_ffa device in tpm_crb_ffa_init() to finish probe the TPM device
completely.

This ensures that the TPM device using CRB over FF-A can be successfully
probed, even if crb_acpi_driver_init() is called first.

[ jarkko: reformatted some of the paragraphs because they were going past
  the 75 character boundary. ]

Signed-off-by: Yeoreum Yun <yeoreum....@arm.com>
Reviewed-by: Mimi Zohar <zo...@linux.ibm.com>
Reviewed-by: Sudeep Holla <sudeep.ho...@arm.com>
Reviewed-by: Jarkko Sakkinen <jar...@kernel.org>
Signed-off-by: Jarkko Sakkinen <jar...@kernel.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---

LLM Generated explanations, may be completely bogus:

**Backport Status: YES**

This commit should be backported to stable kernel trees for the
following reasons:

1. **Fixes a functional bug affecting users**: The commit addresses a
   race condition where IMA (Integrity Measurement Architecture) fails
   to detect TPM devices that use CRB over FF-A, resulting in the
   message "ima: No TPM chip found, activating TPM-bypass!" This
   prevents IMA from generating boot_aggregate logs with TPM PCR values,
   which is a critical security feature.

2. **Small and contained fix**: The change is minimal and focused:
   - Adds a static forward declaration of `tpm_crb_ffa_driver`
   - Modifies `tpm_crb_ffa_init()` to explicitly register the FFA driver
     when built-in
   - Adds conditional compilation guards around `module_ffa_driver()`

3. **No architectural changes**: The fix doesn't introduce new features
   or change the architecture. It simply ensures proper driver
   registration ordering when the driver is built-in.

4. **Clear root cause**: The issue occurs because both
   `crb_acpi_driver_init()` and `tpm_crb_ffa_driver_init()` are
   registered with `device_initcall`, leading to unpredictable
   initialization order. When `crb_acpi_driver_init()` runs first, it
   calls `tpm_crb_ffa_init()` which returns `-ENOENT` because the FFA
   driver hasn't been registered yet.

5. **Security implications**: TPM is a critical security component, and
   IMA's inability to use TPM measurements compromises system integrity
   attestation. This fix ensures security features work as intended.

6. **Minimal risk**: The changes only affect the initialization path
   when `CONFIG_TCG_ARM_CRB_FFA` is built-in (not as a module). The fix:
   - Only executes when `!IS_MODULE(CONFIG_TCG_ARM_CRB_FFA)`
   - Preserves existing error handling
   - Doesn't change the module case behavior

7. **Well-reviewed**: The commit has been reviewed by multiple
   maintainers including Mimi Zohar (IMA maintainer), Sudeep Holla (ARM
   FF-A maintainer), and Jarkko Sakkinen (TPM maintainer).

The fix is important for ARM systems using FF-A to communicate with TPM
devices, ensuring that security features like IMA work correctly when
TPM drivers are built into the kernel.

 drivers/char/tpm/tpm_crb_ffa.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/char/tpm/tpm_crb_ffa.c b/drivers/char/tpm/tpm_crb_ffa.c
index 3169a87a56b6..430b99c04124 100644
--- a/drivers/char/tpm/tpm_crb_ffa.c
+++ b/drivers/char/tpm/tpm_crb_ffa.c
@@ -109,6 +109,7 @@ struct tpm_crb_ffa {
 };
 
 static struct tpm_crb_ffa *tpm_crb_ffa;
+static struct ffa_driver tpm_crb_ffa_driver;
 
 static int tpm_crb_ffa_to_linux_errno(int errno)
 {
@@ -162,13 +163,23 @@ static int tpm_crb_ffa_to_linux_errno(int errno)
  */
 int tpm_crb_ffa_init(void)
 {
+       int ret = 0;
+
+       if (!IS_MODULE(CONFIG_TCG_ARM_CRB_FFA)) {
+               ret = ffa_register(&tpm_crb_ffa_driver);
+               if (ret) {
+                       tpm_crb_ffa = ERR_PTR(-ENODEV);
+                       return ret;
+               }
+       }
+
        if (!tpm_crb_ffa)
-               return -ENOENT;
+               ret = -ENOENT;
 
        if (IS_ERR_VALUE(tpm_crb_ffa))
-               return -ENODEV;
+               ret = -ENODEV;
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(tpm_crb_ffa_init);
 
@@ -341,7 +352,9 @@ static struct ffa_driver tpm_crb_ffa_driver = {
        .id_table = tpm_crb_ffa_device_id,
 };
 
+#ifdef MODULE
 module_ffa_driver(tpm_crb_ffa_driver);
+#endif
 
 MODULE_AUTHOR("Arm");
 MODULE_DESCRIPTION("TPM CRB FFA driver");
-- 
2.39.5


Reply via email to