pcrlock: retry policy submission when PCR values keep changing

make_policy() already retries unsealing the recovery PIN when the TPM
reports that PCR values changed, but the tpm2_policy_super_pcr() call
that builds the policy for that unseal attempt was not covered: a
concurrent PCR extension there aborted the whole operation on the first
try.

This is easy to hit when IMA is enabled (e.g. implicitly through secure
boot), as PCR 10 is extended for every kernel module that gets loaded.

Retry that step within the existing loop, and give the retry budget a
name while at it.

Signed-off-by: Alberto Planas <aplanas@suse.com>
This commit is contained in:
Alberto Planas
2026-09-22 21:31:48 +02:00
committed by Luca Boccassi
parent 1fc5351945
commit 299989fe0b
+16 -2
View File
@@ -124,6 +124,10 @@ COMMAND(
#define PCRLOCK_FILE_SYSTEM_PATH_PREFIX "/var/lib/pcrlock.d/840-file-system-"
#define PCRLOCK_PE_INPUT_MAX (2U * U64_GB)
/* Maximum number of retries when PCR values keep changing while we submit the policy for, or unseal, the
* recovery PIN */
#define PCRLOCK_RETRY_UNSEAL_MAX 16U
/* The default set of PCRs to lock to */
#define DEFAULT_PCR_MASK \
((UINT32_C(1) << TPM2_PCR_PLATFORM_CODE) | \
@@ -3849,6 +3853,16 @@ static int make_policy(bool force, RecoveryPinMode recovery_pin_mode) {
policy_session,
&old_policy.prediction,
old_policy.algorithm);
if (r == -EUCLEAN) {
if (attempt >= PCRLOCK_RETRY_UNSEAL_MAX)
return log_error_errno(r,
"PCR values kept changing while submitting the policy, giving up after %u attempts. "
"Something on this system extends a PCR continuously.",
attempt + 1);
log_debug("Trying again (attempt %u), as PCR values changed while submitting the policy.", attempt + 1);
continue;
}
if (r < 0)
return r;
@@ -3868,12 +3882,12 @@ static int make_policy(bool force, RecoveryPinMode recovery_pin_mode) {
policy_session,
encryption_session,
&secret);
if (r < 0 && (r != -ESTALE || attempt >= 16))
if (r < 0 && (r != -ESTALE || attempt >= PCRLOCK_RETRY_UNSEAL_MAX))
return log_error_errno(r, "Failed to unseal PIN: %m");
if (r == 0)
break;
log_debug("Trying again (attempt %u), as PCR values changed during unlock attempt.", attempt+1);
log_debug("Trying again (attempt %u), as PCR values changed during unlock attempt.", attempt + 1);
}
if (secret.iov_len > sizeof_field(TPM2B_AUTH, buffer))