[PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa

Yeoreum Yun posted 2 patches 4 months ago
drivers/char/tpm/tpm_crb_ffa.c    | 22 +++++++++++++++++-----
drivers/firmware/arm_ffa/driver.c |  2 +-
2 files changed, 18 insertions(+), 6 deletions(-)
[PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
To integrate a TPM device that uses CRB over FF-A with the IMA subsystem,
both the tpm_crb and tpm_crb_ffa drivers must be built as built-in
(i.e., ARM_FFA_TRANSPORT=y, CONFIG_TCG_CRB=y, and CONFIG_TCG_CRB_FFA=y),
because IMA itself is built-in and the TPM device must be probed
before ima_init() is invoked during IMA subsystem initialization.

To ensure this works correctly, the following initcalls must be executed in order:
	1.	ffa_init()
	2.	tpm_crb_ffa_driver_init()
	3.	crb_acpi_driver_init()

Unfortunately, the order of these device initcalls cannot be strictly controlled.
As a result:
	1.	ffa_init() may be called after tpm_crb_ffa_driver_init()
	2.	tpm_crb_ffa_driver_init() may be called after crb_acpi_driver_init()

For example, the following initcall sequence may occur:
  0000000000000888 l  .initcall6.init>  crb_acpi_driver_init
  000000000000088c l  .initcall6.init>  tpm_crb_ffa_driver_init
  0000000000000a9c l  .initcall6.init>  ffa_init

In this situation, the IMA subsystem fails to integrate with the TPM device
because the TPM was not available at the time ima_init() was called.
As a result, you may see the following message in the kernel log:

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

To resolve this issue:
  Patch #1: change the initcall level of ffa_init() to rootfs_initcall,
            so that the FF-A device is created before any FF-A drivers are loaded.

  Patch #2: call ffa_register() in tpm_crb_ffa_init() when it is built as built-in,
            ensuring that the Secure Partition used by tpm_crb_ffa
            is already registered when the TPM device is probed.

==============
Patch History
==============
  Since v1:
     - rewrite commit message.
     - https://lore.kernel.org/all/20250606105754.1202649-1-yeoreum.yun@arm.com/


Yeoreum Yun (2):
  firmware: arm_ffa: Change initcall level of ffa_init() to
    rootfs_initcall
  tpm: tpm_crb_ffa: maunally register tpm_crb_ffa driver when it's
    built-in

 drivers/char/tpm/tpm_crb_ffa.c    | 22 +++++++++++++++++-----
 drivers/firmware/arm_ffa/driver.c |  2 +-
 2 files changed, 18 insertions(+), 6 deletions(-)

--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Jarkko Sakkinen 4 months ago
On Tue, Jun 10, 2025 at 07:03:32AM +0100, Yeoreum Yun wrote:
> To integrate a TPM device that uses CRB over FF-A with the IMA subsystem,
> both the tpm_crb and tpm_crb_ffa drivers must be built as built-in
> (i.e., ARM_FFA_TRANSPORT=y, CONFIG_TCG_CRB=y, and CONFIG_TCG_CRB_FFA=y),
> because IMA itself is built-in and the TPM device must be probed
> before ima_init() is invoked during IMA subsystem initialization.

The description of the problem and motivation to solve it should be
first; not the actions taken.

> 
> To ensure this works correctly, the following initcalls must be executed in order:
> 	1.	ffa_init()
> 	2.	tpm_crb_ffa_driver_init()
> 	3.	crb_acpi_driver_init()
> 
> Unfortunately, the order of these device initcalls cannot be strictly controlled.
> As a result:
> 	1.	ffa_init() may be called after tpm_crb_ffa_driver_init()
> 	2.	tpm_crb_ffa_driver_init() may be called after crb_acpi_driver_init()
> 
> For example, the following initcall sequence may occur:
>   0000000000000888 l  .initcall6.init>  crb_acpi_driver_init
>   000000000000088c l  .initcall6.init>  tpm_crb_ffa_driver_init

This symbol does not exist.

>   0000000000000a9c l  .initcall6.init>  ffa_init
> 
> In this situation, the IMA subsystem fails to integrate with the TPM device
> because the TPM was not available at the time ima_init() was called.
> As a result, you may see the following message in the kernel log:
> 
>   | ima: No TPM chip found, activating TPM-bypass!

TPM initializes before IMA, so there should not be a problem.

BR, Jarkko
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
Hi Jarkko,

> On Tue, Jun 10, 2025 at 07:03:32AM +0100, Yeoreum Yun wrote:
> > To integrate a TPM device that uses CRB over FF-A with the IMA subsystem,
> > both the tpm_crb and tpm_crb_ffa drivers must be built as built-in
> > (i.e., ARM_FFA_TRANSPORT=y, CONFIG_TCG_CRB=y, and CONFIG_TCG_CRB_FFA=y),
> > because IMA itself is built-in and the TPM device must be probed
> > before ima_init() is invoked during IMA subsystem initialization.
>
> The description of the problem and motivation to solve it should be
> first; not the actions taken.

Okay. I'll describe the problem first.

>
> >
> > To ensure this works correctly, the following initcalls must be executed in order:
> > 	1.	ffa_init()
> > 	2.	tpm_crb_ffa_driver_init()
> > 	3.	crb_acpi_driver_init()
> >
> > Unfortunately, the order of these device initcalls cannot be strictly controlled.
> > As a result:
> > 	1.	ffa_init() may be called after tpm_crb_ffa_driver_init()
> > 	2.	tpm_crb_ffa_driver_init() may be called after crb_acpi_driver_init()
> >
> > For example, the following initcall sequence may occur:
> >   0000000000000888 l  .initcall6.init>  crb_acpi_driver_init
> >   000000000000088c l  .initcall6.init>  tpm_crb_ffa_driver_init
>
> This symbol does not exist.

I don't know you said "This symbol does not exit".
When CONFIG_TCG=CRB=y, CONFIG_TCG_CRB_FFA=y and ARM_FFA_TRANSPORT=y,
above symbols exist.

crb_acpi_driver_init() generated by
  module_acpi_driver(crb_acpi_driver);
in tpm_crb.c

and tpm_crb_ffa_driver_init() generated by
  module_ffa_driver(tpm_crb_ffa_driver);
in tpm_crb_ffa.c so you can get the above symbols:

$ llvm-readelf-21 --symbols vmlinux | grep crb | grep init
171332: ffff80008203ef08    56 FUNC    LOCAL  DEFAULT    19 crb_acpi_driver_init
...
370077: ffff800080d650d8    92 FUNC    GLOBAL DEFAULT     2 tpm_crb_ffa_init

>
> >   0000000000000a9c l  .initcall6.init>  ffa_init
> >
> > In this situation, the IMA subsystem fails to integrate with the TPM device
> > because the TPM was not available at the time ima_init() was called.
> > As a result, you may see the following message in the kernel log:
> >
> >   | ima: No TPM chip found, activating TPM-bypass!
>
> TPM initializes before IMA, so there should not be a problem.

If you see my commit message it describes the situation why this happen.
when crb_acpi_driver_init() is called but before tpm_crb_ffa_init() is
called, the secure partition doesn't probe. so crb_acpi_driver_init()
would be failed wiith -EPROBE.

In this situation, init_ima() which call ima_init() can be called first.
NOTE, init_ima() is deployed in late_initcall and
the "deferred_probe device" is tried again in
deferred_probe late initcall.
However, even the deferred_probe can be call later then init_ima().

000000000000012c l       .initcall7.init>-------0000000000000000 init_ima
000000000000016c l       .initcall7.init>-------0000000000000000 deferred_probe_initcall7

That's why init_ima() is failed to init with TPM when It is deffered.

Would you let me know why you said it's not a problem?

--
Sincerely,
Yeoreum Yun
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Jarkko Sakkinen 4 months ago
On Tue, Jun 10, 2025 at 02:18:29PM +0100, Yeoreum Yun wrote:
>   module_ffa_driver(tpm_crb_ffa_driver);

Oops, I missed this statement. Sorry, my bad.

> 
> >
> > >   0000000000000a9c l  .initcall6.init>  ffa_init
> > >
> > > In this situation, the IMA subsystem fails to integrate with the TPM device
> > > because the TPM was not available at the time ima_init() was called.
> > > As a result, you may see the following message in the kernel log:
> > >
> > >   | ima: No TPM chip found, activating TPM-bypass!
> >
> > TPM initializes before IMA, so there should not be a problem.
> 
> If you see my commit message it describes the situation why this happen.
> when crb_acpi_driver_init() is called but before tpm_crb_ffa_init() is
> called, the secure partition doesn't probe. so crb_acpi_driver_init()
> would be failed wiith -EPROBE.

What is "secure partition" and why it doesn't probe at the time of
crb_acpi_driver_init()?

> 
> In this situation, init_ima() which call ima_init() can be called first.
> NOTE, init_ima() is deployed in late_initcall and
> the "deferred_probe device" is tried again in
> deferred_probe late initcall.
> However, even the deferred_probe can be call later then init_ima().
> 
> 000000000000012c l       .initcall7.init>-------0000000000000000 init_ima
> 000000000000016c l       .initcall7.init>-------0000000000000000 deferred_probe_initcall7
> 
> That's why init_ima() is failed to init with TPM when It is deffered.
> 
> Would you let me know why you said it's not a problem?

What has deferred_probe_initcall has to do with this? Not actually
asking just pointing out stuff that you should open up.

> 
> --
> Sincerely,
> Yeoreum Yun

BR, Jarkko
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
Hi Jarkko,

[...]
>
> >
> > >
> > > >   0000000000000a9c l  .initcall6.init>  ffa_init
> > > >
> > > > In this situation, the IMA subsystem fails to integrate with the TPM device
> > > > because the TPM was not available at the time ima_init() was called.
> > > > As a result, you may see the following message in the kernel log:
> > > >
> > > >   | ima: No TPM chip found, activating TPM-bypass!
> > >
> > > TPM initializes before IMA, so there should not be a problem.
> >
> > If you see my commit message it describes the situation why this happen.
> > when crb_acpi_driver_init() is called but before tpm_crb_ffa_init() is
> > called, the secure partition doesn't probe. so crb_acpi_driver_init()
> > would be failed wiith -EPROBE.
>
> What is "secure partition" and why it doesn't probe at the time of
> crb_acpi_driver_init()?

secure partition is a secure service provider and among this service,
there is TPM services using CRB over FF-A.

This service is represented with "ffa_device" generated in
ffa_init() in arm_ffa driver.

tpm_crb_ffa driver attaches to this device and provide the interface to
tpm_crb for communicating TPM device via CRB over FF-A.

tpm_crb can communicate this TPM device after this ffa_device is probed.
Therefore to probe the tpm_crb which uses CRB over FF-A:
  1. related ffa_device should be registered which is done via ffa_init().
  2. tpm_crb_driver success to probe above device which is done
     via tpm_crb_ffa_init().
  3. tpm_crb which uses CRB over FF-A can be probed above this is
     probed. -- See crb_acpi_add() and tpm_crb_ffa_init().

Unfortunately, when they're built as built-in,
ffa_init(), tpm_crb_ffa_init() and crb_acpi_driver_init() are deployed in
device_initcall. So, If crb_acpi_driver_init() is called,
If there is no ffa_device or ffa_device isn't probe yet,
It returns -EPROBE in crb_acpi_driver_init() so it's delayed to probe
to deferred_probe_initcall.


A secure partition is a secure service provider.
Among the services it offers, one includes TPM services that
use the CRB interface over FF-A (Firmware Framework for Arm).

This service is represented by an ffa_device, which is created
during the ffa_init() routine in the arm_ffa driver.
The tpm_crb_ffa driver attaches to this ffa_device and
provides an interface to the tpm_crb driver,
enabling communication with the TPM device via CRB over FF-A.

The tpm_crb driver can only communicate with the TPM device
once the corresponding ffa_device has been probed.

Therefore, for a tpm_crb driver that uses CRB over FF-A to be probed properly:
  1. The associated ffa_device must be registered, which happens via ffa_init().
  2. The tpm_crb_driver must successfully probe this device through tpm_crb_ffa_init().
  3. Once that is complete, the tpm_crb driver using CRB over FF-A can then be probed.
     See crb_acpi_add() and tpm_crb_ffa_init() for details.

Unfortunately, when these components are built as built-in drivers,
the functions ffa_init(), tpm_crb_ffa_init(), and crb_acpi_driver_init() are
all executed during the device_initcall phase.
As a result, if crb_acpi_driver_init() is called before the ffa_device exists or
has been probed, it returns -EPROBE_DEFER,
causing the probe to be deferred and retried later
during the deferred_probe_initcall phase.

>
> >
> > In this situation, init_ima() which call ima_init() can be called first.
> > NOTE, init_ima() is deployed in late_initcall and
> > the "deferred_probe device" is tried again in
> > deferred_probe late initcall.
> > However, even the deferred_probe can be call later then init_ima().
> >
> > 000000000000012c l       .initcall7.init>-------0000000000000000 init_ima
> > 000000000000016c l       .initcall7.init>-------0000000000000000 deferred_probe_initcall7
> >
> > That's why init_ima() is failed to init with TPM when It is deffered.
> >
> > Would you let me know why you said it's not a problem?
>
> What has deferred_probe_initcall has to do with this? Not actually
> asking just pointing out stuff that you should open up.

What I want to point out is that
If the TPM device is failed to init in its initcall, and defered
the IMA can be failed to find out the TPM device
since init_ima() is called first before deferred_probe_initcall.

--
Sincerely,
Yeoreum Yun
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Jarkko Sakkinen 4 months ago
On Tue, Jun 10, 2025 at 03:38:27PM +0100, Yeoreum Yun wrote:
> Unfortunately, when these components are built as built-in drivers,
> the functions ffa_init(), tpm_crb_ffa_init(), and crb_acpi_driver_init() are
> all executed during the device_initcall phase.
> As a result, if crb_acpi_driver_init() is called before the ffa_device exists or
> has been probed, it returns -EPROBE_DEFER,

Please mention exactly this in the commit explicitly and then it should
be in detail enough.

> causing the probe to be deferred and retried later
> during the deferred_probe_initcall phase.

OK, if ffa_init() is leveled up in the initcall hierarchy, shouldn't
that be enough as long as ko's can be found from initramfs?

BR, Jarkko
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
Hi Jarkko,

> > Unfortunately, when these components are built as built-in drivers,
> > the functions ffa_init(), tpm_crb_ffa_init(), and crb_acpi_driver_init() are
> > all executed during the device_initcall phase.
> > As a result, if crb_acpi_driver_init() is called before the ffa_device exists or
> > has been probed, it returns -EPROBE_DEFER,
>
> Please mention exactly this in the commit explicitly and then it should
> be in detail enough.

Okay. I'll add this in the next round in cover letter.

>
> > causing the probe to be deferred and retried later
> > during the deferred_probe_initcall phase.
>
> OK, if ffa_init() is leveled up in the initcall hierarchy, shouldn't
> that be enough as long as ko's can be found from initramfs?

As you mentioned, this is handled in Patch #1.
However, although ffa_init() is called first,
unless tpm_crb_ffa_init() is also invoked,
crb_acpi_driver_init() will fail with -EPROBE_DEFER.

Please note that IMA is always built-in and cannot be built as a module.
To generate boot_aggregate with TPM PCR values from 0 to 7,
the TPM-related modules must also be built-in and
properly initialized before init_ima(), which internally calls ima_init().

To ensure this, Patch #2 adds a routine to probe
the ffa_device() in tpm_crb_ffa_init().
This allows crb_acpi_driver_init() to successfully complete even if
it is called first, because tpm_crb_ffa_init() triggers
probing of the ffa_device via ffa_register() beforehand.

Thanks.
--
Sincerely,
Yeoreum Yun
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Jarkko Sakkinen 4 months ago
On Tue, Jun 10, 2025 at 04:22:04PM +0100, Yeoreum Yun wrote:
> > OK, if ffa_init() is leveled up in the initcall hierarchy, shouldn't
> > that be enough as long as ko's can be found from initramfs?
> 
> As you mentioned, this is handled in Patch #1.
> However, although ffa_init() is called first,
> unless tpm_crb_ffa_init() is also invoked,
> crb_acpi_driver_init() will fail with -EPROBE_DEFER.
> 
> Please note that IMA is always built-in and cannot be built as a module.

Sure but if one needs IMA, then tpm_crb_ffa can be compiled as built-in
with zero code changes.

BR, Jarkko
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
Hi Jarkko,

> On Tue, Jun 10, 2025 at 04:22:04PM +0100, Yeoreum Yun wrote:
> > > OK, if ffa_init() is leveled up in the initcall hierarchy, shouldn't
> > > that be enough as long as ko's can be found from initramfs?
> >
> > As you mentioned, this is handled in Patch #1.
> > However, although ffa_init() is called first,
> > unless tpm_crb_ffa_init() is also invoked,
> > crb_acpi_driver_init() will fail with -EPROBE_DEFER.
> >
> > Please note that IMA is always built-in and cannot be built as a module.
>
> Sure but if one needs IMA, then tpm_crb_ffa can be compiled as built-in
> with zero code changes.

All of my describtion based on all things are built as "built-in".
in case of ffa_init() changes the init level to root_initcall,
so, the ffa_device will be produced first before the trial of TPM probe.

Note that tpm_crb_ffa_init() which is the "ffa_driver" is called in
device_initcall level. I mean

    ffa_init() -> arm_ffa -> root_initcall
    tpm_crb_ffa_init() -> device_initcall
    crb_acpi_driver_init() -> device_initcall

therefore, "crb_acpi_driver_init()" can be call first before
tpm_crb_ffa_init() since they're deployed in device_initcall.
If this happen, "crb_acpi_driver_init()" failed with -EPROBE_DEFER.

That's why this patch is required to probe "tpm_crb_ffa" when
crb_acpi_driver_init() called to complete the TPM device probe before
IMA subsystem initailization.

Thanks.

--
Sincerely,
Yeoreum Yun
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Jarkko Sakkinen 4 months ago
On Wed, Jun 11, 2025 at 06:36:02PM +0100, Yeoreum Yun wrote:
> Hi Jarkko,
> 
> > On Tue, Jun 10, 2025 at 04:22:04PM +0100, Yeoreum Yun wrote:
> > > > OK, if ffa_init() is leveled up in the initcall hierarchy, shouldn't
> > > > that be enough as long as ko's can be found from initramfs?
> > >
> > > As you mentioned, this is handled in Patch #1.
> > > However, although ffa_init() is called first,
> > > unless tpm_crb_ffa_init() is also invoked,
> > > crb_acpi_driver_init() will fail with -EPROBE_DEFER.
> > >
> > > Please note that IMA is always built-in and cannot be built as a module.
> >
> > Sure but if one needs IMA, then tpm_crb_ffa can be compiled as built-in
> > with zero code changes.
> 
> All of my describtion based on all things are built as "built-in".
> in case of ffa_init() changes the init level to root_initcall,
> so, the ffa_device will be produced first before the trial of TPM probe.
> 
> Note that tpm_crb_ffa_init() which is the "ffa_driver" is called in
> device_initcall level. I mean
> 
>     ffa_init() -> arm_ffa -> root_initcall
>     tpm_crb_ffa_init() -> device_initcall
>     crb_acpi_driver_init() -> device_initcall
> 
> therefore, "crb_acpi_driver_init()" can be call first before
> tpm_crb_ffa_init() since they're deployed in device_initcall.
> If this happen, "crb_acpi_driver_init()" failed with -EPROBE_DEFER.
> 
> That's why this patch is required to probe "tpm_crb_ffa" when
> crb_acpi_driver_init() called to complete the TPM device probe before
> IMA subsystem initailization.

Yep, and you sort it out by not compiling it as a module.

+	ret = ffa_register(&tpm_crb_ffa_driver);
+	BUG_ON(!ret && !tpm_crb_ffa);

These lines struck me in your patch. The commit message has nothing
about ffa_register().

Also, please remove BUG_ON(). That said, I don't think 2/2 is needed.

> 
> Thanks.
> 
> --
> Sincerely,
> Yeoreum Yun


BR, Jarkko
Re: [PATCH v2 0/2] fix failure of integration IMA with tpm_crb_ffa
Posted by Yeoreum Yun 4 months ago
Hi Jarkko,

[...]
> Yep, and you sort it out by not compiling it as a module.
>
> +	ret = ffa_register(&tpm_crb_ffa_driver);
> +	BUG_ON(!ret && !tpm_crb_ffa);
>
> These lines struck me in your patch. The commit message has nothing
> about ffa_register().


Sorry. I think I miss the description for this detail.

This is core of this patch.
So, in patch #1, by chaning the ffa_init() to rootfs_initcall,
it ensures the generation of "tpm_crb_ffa device" is created before
crb_acpi_driver_init() but "tpm_crb_ffa device" isn't probe yet since
the "tpm_crb_ffa driver" isn't yet registered which is registered by
"tpm_crb_ffa_init()".

Therefore, this patch does that when crb_acpi_driver_init() is called first,
tpm_crb_init() registers "tpm_crb_ffa driver" via "ffa_register()"
to trigger probing of "tpm_crb_ffa device" to initalize
the TPM device using CRB over FF-A.

>
> Also, please remove BUG_ON(). That said, I don't think 2/2 is needed.

Okay. I'll replace it with error message.

Thanks.

--
Sincerely,
Yeoreum Yun