tpm2-util: make -EUCLEAN from tpm2_unseal() mean "PCRs kept changing"
So far tpm2_unseal() used -EUCLEAN together with the errors that signal that the PCR state does not match the policy. That is misleading: -EUCLEAN (and TPM2_RC_PCR_CHANGED) is only ever generated when the TPM's global PCR update counter moves while we are building the policy or unsealing, i.e. when something on the system extends a PCR concurrentlyi (usually IMA extending PCR 10). It says nothing about whether the policy itself matches. Until now the retry loop only recognized those conditions while retries were left (i > 0), and once the budget was exhausted the last iteration fell through to the generic paths, reporting either an unrelated policy error or -ENOTRECOVERABLE. Handle the last iteration explicitly instead, and return -EUCLEAN with a message that names the actual problem. Drop -EUCLEAN from ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(), it is not a "bad PCR state" error. Signed-off-by: Alberto Planas <aplanas@suse.com>
This commit is contained in:
committed by
Luca Boccassi
parent
c99af7968e
commit
2d54e6b56e
+16
-5
@@ -7197,13 +7197,17 @@ int tpm2_unseal(Tpm2Context *c,
|
||||
* -ENOLCK → TPM is in dictionary lockout mode
|
||||
* -EREMCHG → submitted policy doesn't match NV index stored policy (in case of PolicyAuthorizeNV)
|
||||
* -ENOANO → none of the PolicyOR branches of a policy matched current state
|
||||
* -EUCLEAN → PCR state doesn't match expectations
|
||||
* -EUCLEAN → a PCR kept being extended while we were unsealing
|
||||
* -EPERM → stored policy does not match TPM state
|
||||
* -ENOTRECOVERABLE → all other kinds of TPM errors
|
||||
* -EILSEQ → bad PIN
|
||||
*
|
||||
* Of these all four of EREMCHG, ENOANO, EUCLEAN, EPERM can all mean that PCR state is not matching
|
||||
* expectations. */
|
||||
* Of these EREMCHG, ENOANO and EPERM mean that PCR state is not matching expectations. EUCLEAN on
|
||||
* the other hand says nothing about the correctness of the policy: it means the TPM's global PCR
|
||||
* update counter kept moving while we built the policy or unsealed, i.e. something on this system
|
||||
* extends a PCR continuously (the usual suspect is PCR 10 when IMA is enabled directly, or
|
||||
* indirectly via secure boot). We make at most RETRY_UNSEAL_MAX + 1 attempts before reporting
|
||||
* it. */
|
||||
|
||||
TSS2_RC rc;
|
||||
int r;
|
||||
@@ -7361,7 +7365,10 @@ int tpm2_unseal(Tpm2Context *c,
|
||||
!!pin,
|
||||
(shard == 1 || !iovec_is_set(pubkey)) ? pcrlock_policy : NULL,
|
||||
&policy_digest);
|
||||
if (r == -EUCLEAN && i > 0) {
|
||||
if (r == -EUCLEAN) {
|
||||
if (i == 0)
|
||||
return log_debug_errno(r, "PCR values kept changing while building the TPM2 policy, giving up after %u unsealing attempts.", RETRY_UNSEAL_MAX + 1);
|
||||
|
||||
log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
|
||||
retry = true;
|
||||
break;
|
||||
@@ -7403,7 +7410,11 @@ int tpm2_unseal(Tpm2Context *c,
|
||||
encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
|
||||
ESYS_TR_NONE,
|
||||
&unsealed);
|
||||
if (rc == TPM2_RC_PCR_CHANGED && i > 0) {
|
||||
if (rc == TPM2_RC_PCR_CHANGED) {
|
||||
if (i == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
||||
"PCR values kept changing while unsealing, giving up after %u unsealing attempts.", RETRY_UNSEAL_MAX + 1);
|
||||
|
||||
log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
|
||||
retry = true;
|
||||
break;
|
||||
|
||||
@@ -51,8 +51,10 @@ static inline bool TPM2_PCR_MASK_VALID(uint32_t pcr_mask) {
|
||||
int dlopen_tpm2(int log_level) _dlopen_loader_;
|
||||
|
||||
/* tpm2_unseal() returns a bunch of different errors for various flavours of PCR issues, let's group them.
|
||||
* Kept outside the HAVE_TPM2 guard as callers switch on these errnos even in builds without TPM2. */
|
||||
#define ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r) IN_SET(r, -EREMCHG, -ENOANO, -EUCLEAN, -EPERM)
|
||||
* Kept outside the HAVE_TPM2 guard as callers switch on these errnos even in builds without TPM2. Note that
|
||||
* -EUCLEAN is not part of this: when returned by tpm2_unseal() it means a PCR was continuously extended
|
||||
* while unsealing, which says nothing about whether the PCR state matches the policy. */
|
||||
#define ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r) IN_SET(r, -EREMCHG, -ENOANO, -EPERM)
|
||||
|
||||
/* Errors that mean the tried TPM2 token does not match the boot state, be it due to wrong PCR state, a
|
||||
* different PCR signing key/policy, a different TPM, or an unusable NV index. The caller should keep trying
|
||||
|
||||
Reference in New Issue
Block a user