]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cryptsetup: Give NV index missing its own error code
authorKai Lüke <kai@amutable.com>
Mon, 6 Jul 2026 13:54:38 +0000 (22:54 +0900)
committerKai Lüke <pothos@users.noreply.github.com>
Fri, 10 Jul 2026 06:07:47 +0000 (08:07 +0200)
To be able to continue trying other tokens to unlock a disk the missing
NV index case was mapped to EREMOTE (foreign TPM) which was ok because
this mostly happens when trying to unlock on another system. Still it
might be useful to deal with NV index errors differently.
Give it its own EADDRNOTAVAIL error and handle it at all call sites.

src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
src/shared/creds-util.c
src/shared/cryptsetup-tpm2.c
src/shared/tpm2-util.c
src/shared/tpm2-util.h
src/shared/varlink-io.systemd.Credentials.c

index 9c73463debe026c401528fbae65bddb08c576346..af2b2b74776d688d611cce4728cd9a4d3ea33ab1 100644 (file)
@@ -31,7 +31,7 @@ static int log_debug_open_error(struct crypt_device *cd, int token, int r) {
                 (void) crypt_log_debug_errno(cd, r, "Token %d: no matching TPM2 token data found.", token);
                 return -EPERM;
         }
-        if (IN_SET(r, -EREMCHG, -EREMOTE)) {
+        if (IN_SET(r, -EREMCHG, -EREMOTE, -EADDRNOTAVAIL)) {
                 /* Remap as above. Note: For now without -EUCLEAN because currently the only error it
                  * reports won't be solved by moving to another token. */
                 (void) crypt_log_debug_errno(cd, r, "Token %d: TPM policy does not match current system state, skipping.", token);
index d53b00518c708b85490070e9baaf2cf065ff2d5f..e88d1594747491df2f3cb7105943e47c7f576a1f 100644 (file)
@@ -112,7 +112,9 @@ int acquire_luks2_key(
                         srk,
                         ret_decrypted_key);
         if (r == -EREMOTE)
-                return log_warning_errno(r, "TPM key integrity check failed or NV index unusable. Key enrolled in superblock most likely does not belong to this TPM.");
+                return log_warning_errno(r, "TPM key integrity check failed. Key enrolled in superblock most likely does not belong to this TPM.");
+        if (r == -EADDRNOTAVAIL)
+                return log_warning_errno(r, "NV index referenced by token is missing, unwritten, or unusable, it could be for another system.");
         if (r == -EILSEQ)
                 return log_error_errno(SYNTHETIC_ERRNO(ENOANO), "Bad PIN."); /* cryptsetup docs say we should return ENOANO on bad PIN */
         if (r == -ENOLCK)
index eaee54ee57abc288844cdf18af53b5c6b3318df0..54a8a9abead4d3f8a616d11780580bc22450beba 100644 (file)
@@ -1393,6 +1393,8 @@ int decrypt_credential_and_warn(
                                 &tpm2_key);
                 if (r == -EREMOTE)
                         return log_error_errno(r, "TPM key integrity check failed. Key most likely does not belong to this TPM.");
+                if (r == -EADDRNOTAVAIL)
+                        return log_error_errno(r, "NV index referenced by key is missing, unwritten, or unusable, it could be for another system.");
                 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 (r < 0)
@@ -1837,6 +1839,7 @@ static const CredentialsVarlinkError credentials_varlink_error_table[] = {
         { "io.systemd.Credentials.KeyBelongsToOtherTPM",   EREMOTE,      "The TPM integrity check for this key failed, key probably belongs to another TPM, or was corrupted." },
         { "io.systemd.Credentials.TPMInDictionaryLockout", ENOLCK,       "The TPM is in dictionary lockout mode, cannot operate." },
         { "io.systemd.Credentials.UnexpectedPCRState" ,    EUCLEAN,      "Unexpected TPM PCR state of the system." },
+        { "io.systemd.Credentials.NVIndexUnusable",        EADDRNOTAVAIL, "The NV index referenced by the key is missing, unwritten, or unusable, it could be for another system." },
 };
 
 const CredentialsVarlinkError* credentials_varlink_error_by_id(const char *id) {
index cd7a1506a1d12af03b82c1e98cd77a8b227c2a61..a34c87cb917448221b8d32e9e57e8b1730f8c700 100644 (file)
@@ -174,7 +174,9 @@ int acquire_tpm2_key(
                                 srk,
                                 ret_decrypted_key);
                 if (r == -EREMOTE)
-                        return log_warning_errno(r, "TPM key integrity check failed or NV index unusable. Key enrolled in superblock most likely does not belong to this TPM.");
+                        return log_warning_errno(r, "TPM key integrity check failed. Key enrolled in superblock most likely does not belong to this TPM.");
+                if (r == -EADDRNOTAVAIL)
+                        return log_warning_errno(r, "NV index referenced by token is missing, unwritten, or unusable, it could be for another system.");
                 if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) {
                         log_warning_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. */
@@ -232,7 +234,9 @@ int acquire_tpm2_key(
                                 srk,
                                 ret_decrypted_key);
                 if (r == -EREMOTE)
-                        return log_warning_errno(r, "TPM key integrity check failed or NV index unusable. Key enrolled in superblock most likely does not belong to this TPM.");
+                        return log_warning_errno(r, "TPM key integrity check failed. Key enrolled in superblock most likely does not belong to this TPM.");
+                if (r == -EADDRNOTAVAIL)
+                        return log_warning_errno(r, "NV index referenced by token is missing, unwritten, or unusable, it could be for another system.");
                 if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r)) {
                         log_warning_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. */
index 3a6afdb95c71d6add4d9c70806073e15273addd5..11ae999093a3643113b3ca9901d704615a9bf246 100644 (file)
@@ -4753,8 +4753,8 @@ int tpm2_policy_authorize_nv(
                                        "Submitted policy does not match policy stored in PolicyAuthorizeNV.");
         if ((rc & ~(TPM2_RC_N_MASK|TPM2_RC_P)) == TPM2_RC_HANDLE ||
             rc == TPM2_RC_NV_UNINITIALIZED) /* NV index is missing, unwritten, or otherwise unusable for this policy (or: wrong authHandle/policySession). */
-                return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE),
-                                       "NV index referenced by token is missing, unwritten, or unusable.");
+                return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                       "NV index referenced by token is missing, unwritten, or unusable, it could be for another system.");
         if (rc != TSS2_RC_SUCCESS)
                 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                        "Failed to add AuthorizeNV policy to TPM: %s",
@@ -6667,7 +6667,8 @@ int tpm2_unseal(Tpm2Context *c,
 
         /* Returns the following errors:
          *
-         *   -EREMOTE         → blob is from a different TPM, or NV index referenced by policy is unusable
+         *   -EREMOTE         → blob is from a different TPM
+         *   -EADDRNOTAVAIL   → NV index referenced by policy is missing, unwritten, or unusable
          *   -ENOSTR          → signature JSON has no matching entry for the current PCR policy
          *   -EDEADLK         → couldn't create primary key because authorization failure
          *   -ENOLCK          → TPM is in dictionary lockout mode
index 5f60788869f908a0c8d9e7e315797600f5444b62..ea69940701e4f670c595ebc85f6d3fb2bc71d2f7 100644 (file)
@@ -54,8 +54,9 @@ int dlopen_tpm2(int log_level);
 #define ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r) IN_SET(r, -EREMCHG, -ENOANO, -EUCLEAN, -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, or even a different TPM. The caller should keep trying other tokens. */
-#define ERRNO_IS_NEG_TPM2_TOKEN_MISMATCH(r) IN_SET(r, -EREMCHG, -ENOANO, -EPERM, -ENOSTR, -EREMOTE)
+ * different PCR signing key/policy, a different TPM, or an unusable NV index. The caller should keep trying
+ * other tokens. */
+#define ERRNO_IS_NEG_TPM2_TOKEN_MISMATCH(r) IN_SET(r, -EREMCHG, -ENOANO, -EPERM, -ENOSTR, -EREMOTE, -EADDRNOTAVAIL)
 
 #if HAVE_TPM2
 #ifndef SYSTEMD_CFLAGS_MARKER_TPM2
index 975e992f169aba42c477927cc009998a81786989..cec70e22003e0607dcda6716642e0f0e069828ca 100644 (file)
@@ -79,6 +79,7 @@ static SD_VARLINK_DEFINE_ERROR(NullKeyNotAllowed);
 static SD_VARLINK_DEFINE_ERROR(KeyBelongsToOtherTPM);
 static SD_VARLINK_DEFINE_ERROR(TPMInDictionaryLockout);
 static SD_VARLINK_DEFINE_ERROR(UnexpectedPCRState);
+static SD_VARLINK_DEFINE_ERROR(NVIndexUnusable);
 
 SD_VARLINK_DEFINE_INTERFACE(
                 io_systemd_Credentials,
@@ -111,4 +112,6 @@ SD_VARLINK_DEFINE_INTERFACE(
                 SD_VARLINK_SYMBOL_COMMENT("The TPM is in dictionary lockout mode, cannot operate."),
                 &vl_error_TPMInDictionaryLockout,
                 SD_VARLINK_SYMBOL_COMMENT("Unexpected TPM PCR state of the system."),
-                &vl_error_UnexpectedPCRState);
+                &vl_error_UnexpectedPCRState,
+                SD_VARLINK_SYMBOL_COMMENT("The NV index referenced by the key is missing, unwritten, or unusable, it could be for another system."),
+                &vl_error_NVIndexUnusable);