From 299989fe0bac97e6df9f69ca0af72892808d8d0b Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Mon, 14 Sep 2026 10:41:06 +0200 Subject: [PATCH] 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 --- src/pcrlock/pcrlock.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index 4f5a384072..8906cdff25 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -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))