-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Make IMA able to wait and correctly detect the TPM device #5003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…bled Co-authored-by: Davide Scovotto <[email protected]> Co-developed-by: Davide Scovotto <[email protected]> Signed-off-by: Davide Scovotto <[email protected]> Signed-off-by: Alberto Solavagione <[email protected]>
…r and device registration when IMA is enabled Co-authored-by: Alberto Solavagione <[email protected]> Co-developed-by: Alberto Solavagione <[email protected]> Signed-off-by: Alberto Solavagione <[email protected]> Signed-off-by: Davide Scovotto <[email protected]>
I would appreciate if security related and critical changes are send to the official kernel mailing lists for a review. |
@lategoodbye Ok, thank you very much. Could you tell us who we should contact? We were thinking to contact IMA/TPM mantainers, do you think it's the best choice? |
@AlbertoSvg To be honest, this wont be trivial like creating a pull request here. At first the issue must be reproduced with a mainline kernel (torvalds tree without optimizations from here). I could prepare a branch (based on 5.18-rcX) with the necessary changes for you. Which Raspberry Pi do you use? |
I've been wary about tampering with the initcall level in the past because of unintended consequences, but as this is conditional on a less common, non-standard (to us) config setting, the chances of anything going wrong are much reduced. |
I'm the co-developer of this PR together with @AlbertoSvg. We thank you for accepting our solution. |
See: raspberrypi/linux#5006 kernel: overlays: Add drm parameter to pitft28-resistive See: raspberrypi/linux#5004 kernel: Make IMA able to wait and correctly detect the TPM device See: raspberrypi/linux#5003
See: raspberrypi/linux#5006 kernel: overlays: Add drm parameter to pitft28-resistive See: raspberrypi/linux#5004 kernel: Make IMA able to wait and correctly detect the TPM device See: raspberrypi/linux#5003
I know this is closed and merged, but I'm still having the same issue even after this PR. My Infineon Optiga SLB 9670 takes a long time to load (17s?!?) and IMA has long given up on it by then. Any thoughts on how/why this is and what I can do to remedy it? Btw, I'm running with your debug patch to add the extra log entry so it's clearly visible when the TPM becomes available.
|
@mpeters If the TPM driver is loaded so late it is probable that you did not set the TPM module as built-in. |
@ScovottoDavide it's using this |
Try to recompile the kernel by modifying this two lines:
To
In this way you enable to load those modules as built-in, and you will see that the loading time of the TPM should reduce by a lot and everything should work. Built-in modules (=y) are loaded before any loadable modules (=m), you have not set SPI to be built-in. |
@ScovottoDavide thanks, that actually helps a lot, but it still doesn't quite get there. After recompiling I get this:
So IMA still checks for the TPM before it's ready, even if the gap is down to 2 seconds now. |
@mpeters Mmm, can you run the kernel by passing the option "initcall_debug" on the command line (cmdline.txt file) and send me the resulting log? |
@ScovottoDavide The whole log? Or just the parts that match |
@ScovottoDavide it appears the
|
full dmeg output here: https://gist.github.com/mpeters/4e31fcba2a70e238cd89bd26630597b7 |
nvm, dtpm is about power management, not the TPM. |
@mpeters You can try to disable these configurations (by setting them to "n"), because i think that linux is choosing another driver and our solution was for the SPI one.
You set to "y" only these ones:
Do you have these two lines set in /boot/config.txt? :
Can you also tell us what is your setup? (raspberry, OS, ...) |
Even with those config options, it's still having the same issue:
My
I'm using a Raspberry Pi 4 B with an Infineon Optiga SLB 9670 TPM chip. I'm running Fedora 35 with a custom built (using the options I've posted above) raspberry PI kernel. |
@mpeters Ok, we have It working on different Raspberry Pis, so It is strange to me that is not working. Your configuration seems also very similar to our, two things that i noticed are different are these lines |
@AlbertoSvg I changed the --- a/drivers/char/tpm/tpm_tis_spi_main.c
+++ b/drivers/char/tpm/tpm_tis_spi_main.c
@@ -243,10 +243,17 @@ static int tpm_tis_spi_driver_probe(struct spi_device *spi)
if (!probe_func) {
if (spi_dev_id) {
probe_func = (tpm_tis_spi_probe_func)spi_dev_id->driver_data;
- if (!probe_func)
+ if (!probe_func) {
return -ENODEV;
- } else
+ } else {
+ pr_info("Probe func found from spi_dev_id\n");
+ }
+ } else {
probe_func = tpm_tis_spi_probe;
+ pr_info("Probe func using tpm_tis_spi_probe\n");
+ }
+ } else {
+ pr_info("Probe func found from of_device_get_match_data\n");
} And then dmesg gives this:
which is, again, still ~2s after IMA startup. Is this what you were expecting from the probe? |
@mpeters So from our understanding, correct me if I'm wrong, you're not using the default boot loader and you're building the upstream kernel. Just to be sure, are you using the The cause of your problem it may be coming from your custom configuration. This patch has not been tested upstream. P.S. just for curiosity, did you remove the debug line "TPM chip available" that you set up at the beginning? I saw that in your dmesg was not there anymore. |
Yes
Yes, I'm in the
Oh interesting. No, I didn't remove it, but it's not showing up in the output anymore. I missed that. My diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 65d800ecc996..6edd2c932742 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -418,12 +418,14 @@ static int tpm_add_char_device(struct tpm_chip *chip)
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm_devs_add(chip);
if (rc)
goto err_del_cdev;
}
/* Make the chip available. */
mutex_lock(&idr_lock);
idr_replace(&dev_nums_idr, chip, chip->dev_num);
+ pr_info("TPM chip available\n");
mutex_unlock(&idr_lock);
return 0; I'll add a few more debugging statements to see if I can notice why... |
@mpeters This should be the flow of the TPM registration:
The problem could be that you are integrating the upstream kernel with this one. By chance would you be able to give us a detailed description of how to build you custom kernel in order to be able to replicate it and test it? |
Sorry for the delay, but just now coming back to this with more info:
Yeah, not sure why it wasn't there, but that doesn't seem like the problem anymore. I've added a few more debugging lines to static int tpm_add_char_device(struct tpm_chip *chip)
{
int rc;
+ pr_info("mpeters: In tpm_add_char_device\n");
rc = cdev_device_add(&chip->cdev, &chip->dev);
if (rc) {
+ pr_info("mpeters: After cdev_device_add with return code %d\n", rc);
dev_err(&chip->dev,
"unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
dev_name(&chip->dev), MAJOR(chip->dev.devt),
@@ -417,13 +419,16 @@ static int tpm_add_char_device(struct tpm_chip *chip)
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm_devs_add(chip);
+ pr_info("mpeters: After tpm_devs_add with return code %d\n", rc);
if (rc)
goto err_del_cdev;
}
/* Make the chip available. */
+ pr_info("mpeters: Making TPM chip available\n");
mutex_lock(&idr_lock);
idr_replace(&dev_nums_idr, chip, chip->dev_num);
+ pr_info("mpeters: TPM chip available\n");
mutex_unlock(&idr_lock);
return 0; as well as some debug lines at the beginning of each function call you mentioned in the chain (I added a "mpeters: " prefix to those info lines just to make it easier to see) and they are executing as expected, just after IMA is done initializing:
I'm not doing anything with the upstream kernel. I'm just building this one with a custom config (and loading it into a running Fedora raspi).
I'm using this config file: https://gist.github.com/mpeters/c74817e4a862c9583ee9247be17b5650 (which is from a stock F35 kernel but with some options enabled for the broadcom and GPIO modules) and then using
This will create rpm packages in
Nothing too fancy or complicated. So if something is amiss it's probably still in my config file. |
@AlbertoSvg would you mind sharing with me a config file that you use that you know works? |
@mpeters This is our .config: https://gist.github.com/AlbertoSvg/f460e03c6707ad01a2d321a4ff54b003 |
@AlbertoSvg btw, I can confirm that compiling the latest kernel on the raspi itself with the stock config + your additions at the top (enabling IMA and the TPM) does indeed work. So now I need to figure out what differences between this config and the Fedora one are causing the problem... |
Problem:
We encountered a problem with IMA detecting the TPM device.
Here is our .config where we enabled these modules to be built-in:
We have noticed that in the function
ima_init()
there is a call totpm_default_chip()
that should return a valid tpm instance, but it always fails to"No TPM chip found, activating TPM-bypass!\n"
. In that function there is a call toidr_get_next()
which returns NULL because theidr_replace()
function intpm_add_char_device()
is called after the call toima_init()->tpm_default_chip().
We introduced some debugging prints in order to detect the function calls order (Figure 1). In the picture below (Figure 2), we can see that the
idr_replace()
is called at second 2.3 ("tpm: TPM available" print) which is after ima_init calls tpm_default_chip to retrieve the tpm device (which takes only 1.65 seconds).To recap, at second 1.65 IMA did not find any TPM because the TPM device registration/loading finishes later.
Solution:
We managed to get TPM finish before IMA looks for it by making the following changes.
First we postponed the bcm2835 clock driver initialization by substituting the
postcore_initcall(__bcm2835_clk_driver_init)
withsubsys_initcall(__bcm2835_clk_driver_init).
Second we forced the “TPM Driver for native SPI access” to run its probe routine synchronously with driver and device registration when IMA is enabled. In this way we are sure that the TPM registration finishes before IMA starts looking for the TPM device.
In the picture below (Figure 3) we show that IMA successfully found the TPM device and didn’t fall in bypass mode.