From d09e025b85eeb783bd4af97910f9ee77513ae73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20L=C3=BCke?= Date: Mon, 20 Apr 2026 23:07:13 +0900 Subject: [PATCH] cryptsetup: Remap bad PCR set early to EPERM Currently libcryptsetup's look treats ENOANO special because it's used to signal PIN requirement. But the bad PCR set can also contain ENOANO for a mismatch from a PolicyOR branch. To continue iterating, remap the bad PCR set to EPERM early. This would in theory also allow us to simplify the matching for the iteration condition but we leave this as is for now to prevent a future regression. --- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 7 +++++-- src/shared/cryptsetup-tpm2.c | 14 ++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c index 40bc2a8f6f..761eb1f719 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c @@ -117,8 +117,11 @@ int acquire_luks2_key( return log_error_errno(SYNTHETIC_ERRNO(ENOANO), "Bad PIN."); /* cryptsetup docs say we should return ENOANO on bad PIN */ if (r == -ENOLCK) return log_error_errno(r, "TPM is in dictionary attack lock-out mode."); - if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) - return log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) { + log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + /* Normalize to -EPERM so callers don't confuse it with -ENOANO's "needs PIN" meaning. */ + return -EPERM; + } if (r == -ENOSTR) return log_error_errno(r, "No signature for current PCR policy in TPM2 signature JSON, token does not apply to current boot state: %m"); if (r < 0) diff --git a/src/shared/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c index c8c99cacba..66fbfeb18b 100644 --- a/src/shared/cryptsetup-tpm2.c +++ b/src/shared/cryptsetup-tpm2.c @@ -175,8 +175,11 @@ int acquire_tpm2_key( ret_decrypted_key); if (r == -EREMOTE) return log_error_errno(r, "TPM key integrity check failed or NV index unusable. Key enrolled in superblock most likely does not belong to this TPM."); - if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) - return log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) { + log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + /* Normalize to -EPERM so callers don't confuse it with -ENOANO's "needs PIN" meaning. */ + return -EPERM; + } if (r == -ENOSTR) return log_error_errno(r, "No signature for current PCR policy in TPM2 signature JSON, token does not apply to current boot state: %m"); if (r < 0) @@ -230,8 +233,11 @@ int acquire_tpm2_key( ret_decrypted_key); if (r == -EREMOTE) return log_error_errno(r, "TPM key integrity check failed or NV index unusable. Key enrolled in superblock most likely does not belong to this TPM."); - if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) - return log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) { + log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m"); + /* Normalize to -EPERM so callers don't confuse it with -ENOANO's "needs PIN" meaning. */ + return -EPERM; + } if (r == -ENOSTR) return log_error_errno(r, "No signature for current PCR policy in TPM2 signature JSON, token does not apply to current boot state: %m"); if (r == -ENOLCK)