1
This pull request fixes a race condition between tpm_pm_suspend() and
 tpm_hwrng_read() (I think for good now):
 
 https://bugzilla.kernel.org/show_bug.cgi?id=219383
 
 BR, Jarkko
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRE6pSOnaBC00OEHEIaerohdGur0gUCZygPzAAKCRAaerohdGur
 0pVIAQCiPAk03Cz7cHmeDfWr19VJfazDdqYSfm2muGkrK1HamQEAhbruhFlAWChZ
 G6PGBppQkGmGcwLk4LneGtr4FX7yPwY=
 =6DaV
 -----END PGP SIGNATURE-----

Merge tag 'tpmdd-next-6.12-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm fix from Jarkko Sakkinen:
 "Fix a race condition between tpm_pm_suspend() and tpm_hwrng_read() (I
  think for good now)"

* tag 'tpmdd-next-6.12-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  tpm: Lock TPM chip in tpm_pm_suspend() first
This commit is contained in:
Linus Torvalds 2024-11-04 08:00:14 -10:00
commit a0339404fd
2 changed files with 22 additions and 14 deletions

View File

@ -525,10 +525,6 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{ {
struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
/* Give back zero bytes, as TPM chip has not yet fully resumed: */
if (chip->flags & TPM_CHIP_FLAG_SUSPENDED)
return 0;
return tpm_get_random(chip, data, max); return tpm_get_random(chip, data, max);
} }

View File

@ -370,6 +370,13 @@ int tpm_pm_suspend(struct device *dev)
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc) {
/* Can be safely set out of locks, as no action cannot race: */
chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
goto out;
}
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
goto suspended; goto suspended;
@ -377,21 +384,19 @@ int tpm_pm_suspend(struct device *dev)
!pm_suspend_via_firmware()) !pm_suspend_via_firmware())
goto suspended; goto suspended;
rc = tpm_try_get_ops(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) {
if (!rc) { tpm2_end_auth_session(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE);
tpm2_end_auth_session(chip); goto suspended;
tpm2_shutdown(chip, TPM2_SU_STATE);
} else {
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
}
tpm_put_ops(chip);
} }
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
suspended: suspended:
chip->flags |= TPM_CHIP_FLAG_SUSPENDED; chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
tpm_put_ops(chip);
out:
if (rc) if (rc)
dev_err(dev, "Ignoring error %d while suspending\n", rc); dev_err(dev, "Ignoring error %d while suspending\n", rc);
return 0; return 0;
@ -440,11 +445,18 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
/* Give back zero bytes, as TPM chip has not yet fully resumed: */
if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) {
rc = 0;
goto out;
}
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_get_random(chip, out, max); rc = tpm2_get_random(chip, out, max);
else else
rc = tpm1_get_random(chip, out, max); rc = tpm1_get_random(chip, out, max);
out:
tpm_put_ops(chip); tpm_put_ops(chip);
return rc; return rc;
} }