Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package cryptsetup for openSUSE:Factory checked in at 2026-07-10 17:33:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cryptsetup (Old) and /work/SRC/openSUSE:Factory/.cryptsetup.new.1991 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cryptsetup" Fri Jul 10 17:33:36 2026 rev:138 rq:1364661 version:2.8.6 Changes: -------- --- /work/SRC/openSUSE:Factory/cryptsetup/cryptsetup.changes 2026-04-08 17:13:20.730037731 +0200 +++ /work/SRC/openSUSE:Factory/.cryptsetup.new.1991/cryptsetup.changes 2026-07-10 17:34:19.634803255 +0200 @@ -1,0 +2,24 @@ +Mon Jul 6 09:00:09 UTC 2026 - Pedro Monreal <[email protected]> + +- Fix for (bsc#1270254) to avoid undesired pinning of all volume + keys (via the thread keyring) through the caller's credentials + when the kernel opens a file. This is due to the refactoring in + kernel commit a28d893eb327 ("md: port block device access to file") + that accidentally causes the caller's thread keyring to be kept + alive long beyond the caller's lifetime, the kernel part is tracked + in (bsc#1270252). + * Add keyring key type. [b6fb6fc0] + * Load volume keys in intermediary keyring linked in thread + keyring. [413a3dd0] + * Use unique intermediary keyring name per device. [04ef07a7] + * Add regression tests. [bfcb0c38, bb5e8e9f, e6573494, aa214c09] + * Add upstream patches: + - cryptsetup-Add-keyring-key-type.patch + - cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch + - cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch + - cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch + - cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch + - cryptsetup-tests-refactor-keyring-helpers.patch + - cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch + +------------------------------------------------------------------- New: ---- cryptsetup-Add-keyring-key-type.patch cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch cryptsetup-tests-refactor-keyring-helpers.patch cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch ----------(New B)---------- New: * Add upstream patches: - cryptsetup-Add-keyring-key-type.patch - cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch New: - cryptsetup-Add-keyring-key-type.patch - cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch - cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch New: - cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch - cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch - cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch New: - cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch - cryptsetup-tests-refactor-keyring-helpers.patch - cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch New: - cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch - cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch - cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch New: - cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch - cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch - cryptsetup-tests-refactor-keyring-helpers.patch New: - cryptsetup-tests-refactor-keyring-helpers.patch - cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cryptsetup.spec ++++++ --- /var/tmp/diff_new_pack.cNipyy/_old 2026-07-10 17:34:21.610870686 +0200 +++ /var/tmp/diff_new_pack.cNipyy/_new 2026-07-10 17:34:21.610870686 +0200 @@ -30,6 +30,14 @@ Source2: baselibs.conf Source3: cryptsetup.keyring Patch0: cryptsetup-fips140-3.patch +# PATCH-FIX-UPSTREAM bsc#1270254 Load volume keys in intermediary keyring linked in thread keyring +Patch1: cryptsetup-Add-keyring-key-type.patch +Patch2: cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch +Patch3: cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch +Patch4: cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch +Patch5: cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch +Patch6: cryptsetup-tests-refactor-keyring-helpers.patch +Patch7: cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch # 2.6.38 has the required if_alg.h BuildRequires: linux-glibc-devel >= 2.6.38 BuildRequires: fdupes ++++++ cryptsetup-Add-keyring-key-type.patch ++++++ >From b6fb6fc0fdc661afba734f4c29350fa6be2ede8f Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Fri, 19 Jun 2026 16:41:47 +0200 Subject: [PATCH] Add keyring key type. diff --git a/lib/utils_keyring.c b/lib/utils_keyring.c index da1ccd85..86aecfe4 100644 --- a/lib/utils_keyring.c +++ b/lib/utils_keyring.c @@ -32,6 +32,7 @@ static const struct { { BIG_KEY, "big_key" }, { TRUSTED_KEY, "trusted" }, { ENCRYPTED_KEY, "encrypted" }, + { KEYRING_KEY, "keyring" }, }; #include <linux/keyctl.h> diff --git a/lib/utils_keyring.h b/lib/utils_keyring.h index 5809f70d..b910767a 100644 --- a/lib/utils_keyring.h +++ b/lib/utils_keyring.h @@ -17,7 +17,7 @@ typedef int32_t key_serial_t; #endif -typedef enum { LOGON_KEY = 0, USER_KEY, BIG_KEY, TRUSTED_KEY, ENCRYPTED_KEY, INVALID_KEY } key_type_t; +typedef enum { LOGON_KEY = 0, USER_KEY, BIG_KEY, TRUSTED_KEY, ENCRYPTED_KEY, KEYRING_KEY, INVALID_KEY } key_type_t; const char *key_type_name(key_type_t ktype); key_type_t key_type_by_name(const char *name); -- 2.54.0 ++++++ cryptsetup-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch ++++++ >From 413a3dd04ec07ad7c3afaed84561cbc7a42f108f Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Thu, 25 Jun 2026 12:05:53 +0200 Subject: [PATCH] Load volume keys in intermediary keyring linked in thread keyring. Instead of loading volume keys directly in the thread keyring, create an intermediary keyring linked in the thread keyring and load volume keys there. The intermediary keyring is bulk-cleaned on crypt_free(). This avoids undesired pinning of all volume keys (via the thread keyring) through the caller's credentials when the kernel opens a file, as was the case with https://lore.kernel.org/all/[email protected]/ Fixes: #993. diff --git a/lib/internal.h b/lib/internal.h index 24b5bd86..e398d0ae 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -74,7 +74,7 @@ struct volume_key *crypt_volume_key_next(struct volume_key *vk); struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id); void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc); bool crypt_volume_key_is_set(const struct volume_key *vk); -bool crypt_volume_key_upload_kernel_key(struct volume_key *vk); +bool crypt_volume_key_upload_kernel_key(struct volume_key *vk, key_serial_t keyring); void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct volume_key *vk); void crypt_volume_key_drop_kernel_key(struct crypt_device *cd, struct volume_key *vk); @@ -247,9 +247,9 @@ int crypt_keyring_get_keysize_by_name(struct crypt_device *cd, size_t *r_key_size); int crypt_use_keyring_for_vk(struct crypt_device *cd); -void crypt_unlink_key_from_thread_keyring(struct crypt_device *cd, +void crypt_unlink_key_from_keyring(struct crypt_device *cd, key_serial_t key_id); -void crypt_unlink_key_by_description_from_thread_keyring(struct crypt_device *cd, +void crypt_unlink_key_by_description_from_keyring(struct crypt_device *cd, const char *key_description, key_type_t ktype); void crypt_drop_uploaded_keyring_key(struct crypt_device *cd, struct volume_key *vks); diff --git a/lib/setup.c b/lib/setup.c index 560b5e1f..4b051e57 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -54,6 +54,9 @@ struct crypt_device { const char *user_key_name2; key_type_t keyring_key_type; + const char *keyring_description; + key_serial_t keyring_id; + uint64_t data_offset; uint64_t metadata_size; /* Used in LUKS2 format */ uint64_t keyslots_size; /* Used in LUKS2 format */ @@ -4141,6 +4144,15 @@ int crypt_header_is_detached(struct crypt_device *cd) return r ? 0 : 1; } +static void crypt_unlink_keyring_from_thread_keyring(struct crypt_device *cd, + key_serial_t keyring_id) +{ + log_dbg(cd, "Unlinking keyring (id: %" PRIi32 ") from thread keyring.", keyring_id); + + if (keyring_unlink_key_from_thread_keyring(keyring_id)) + log_dbg(cd, "keyring_unlink_key_from_thread_keyring failed with errno %d.", errno); +} + void crypt_free(struct crypt_device *cd) { if (!cd) @@ -4151,6 +4163,11 @@ void crypt_free(struct crypt_device *cd) dm_backend_exit(cd); crypt_free_volume_key(cd->volume_key); + if (cd->keyring_description) { + crypt_unlink_keyring_from_thread_keyring(cd, cd->keyring_id); + free(CONST_CAST(void*)cd->keyring_description); + } + crypt_free_type(cd, NULL); device_free(cd, cd->device); @@ -4335,18 +4352,35 @@ static int resume_luks1_by_volume_key(struct crypt_device *cd, return r; } +static bool unlink_key_from_keyring(struct crypt_device *cd, key_serial_t kid, key_serial_t keyring_id) +{ + log_dbg(cd, "Unlinking volume key (id: %" PRIi32 ") from kernel keyring (id: %" PRIi32 ").", + kid, keyring_id); + + if (!keyring_unlink_key_from_keyring(kid, keyring_id)) + return true; + + log_dbg(cd, "keyring_unlink_key_from_keyring failed with errno %d.", errno); + + return false; +} + +/* internal only */ +void crypt_unlink_key_from_keyring(struct crypt_device *cd, + key_serial_t key_id) +{ + (void)unlink_key_from_keyring(cd, key_id, cd->keyring_id); +} + static void crypt_unlink_key_from_custom_keyring(struct crypt_device *cd, key_serial_t kid) { assert(cd); assert(cd->keyring_to_link_vk); - log_dbg(cd, "Unlinking volume key (id: %" PRIi32 ") from kernel keyring (id: %" PRIi32 ").", - kid, cd->keyring_to_link_vk); - if (!keyring_unlink_key_from_keyring(kid, cd->keyring_to_link_vk)) + if (unlink_key_from_keyring(cd, kid, cd->keyring_to_link_vk)) return; - log_dbg(cd, "keyring_unlink_key_from_keyring failed with errno %d.", errno); log_err(cd, _("Failed to unlink volume key from user specified keyring.")); } @@ -7638,6 +7672,8 @@ int crypt_volume_key_keyring(struct crypt_device *cd __attribute__((unused)), in /* internal only */ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk) { + key_serial_t keyring_id; + if (!vk || !cd) return -EINVAL; @@ -7646,14 +7682,31 @@ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key return -EINVAL; } - log_dbg(cd, "Loading key (type logon, name %s) in thread keyring.", - crypt_volume_key_description(vk)); + if (!cd->keyring_description) { + cd->keyring_description = strdup("cryptsetup-keyring"); + if (!cd->keyring_description) + return -ENOMEM; + + log_dbg(cd, "Loading key (type keyring, name %s) in thread keyring.", cd->keyring_description); + keyring_id = keyring_add_key_in_thread_keyring(KEYRING_KEY, cd->keyring_description, NULL, 0); + if (keyring_id < 0) { + free(CONST_CAST(void*)cd->keyring_description); + cd->keyring_description = NULL; + log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)", errno); + log_err(cd, _("Failed to load key in kernel keyring.")); + return -EINVAL; + } + cd->keyring_id = keyring_id; + } + + log_dbg(cd, "Loading key (type logon, name %s) in %s keyring.", + crypt_volume_key_description(vk), cd->keyring_description); - if (crypt_volume_key_upload_kernel_key(vk)) { + if (crypt_volume_key_upload_kernel_key(vk, cd->keyring_id)) { crypt_set_key_in_keyring(cd, 1); return 0; } else { - log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)", errno); + log_dbg(cd, "keyring_add_key_to_keyring failed (error %d)", errno); log_err(cd, _("Failed to load key in kernel keyring.")); return -EINVAL; } @@ -7769,17 +7822,7 @@ void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring) cd->key_in_keyring = key_in_keyring; } -/* internal only */ -void crypt_unlink_key_from_thread_keyring(struct crypt_device *cd, - key_serial_t key_id) -{ - log_dbg(cd, "Unlinking volume key (id: %" PRIi32 ") from thread keyring.", key_id); - - if (keyring_unlink_key_from_thread_keyring(key_id)) - log_dbg(cd, "keyring_unlink_key_from_thread_keyring failed with errno %d.", errno); -} - -void crypt_unlink_key_by_description_from_thread_keyring(struct crypt_device *cd, +void crypt_unlink_key_by_description_from_keyring(struct crypt_device *cd, const char *key_description, key_type_t ktype) { @@ -7802,7 +7845,7 @@ void crypt_unlink_key_by_description_from_thread_keyring(struct crypt_device *cd return; } - crypt_unlink_key_from_thread_keyring(cd, kid); + crypt_unlink_key_from_keyring(cd, kid); } int crypt_set_keyring_to_link(struct crypt_device *cd, const char *key_description, diff --git a/lib/volumekey.c b/lib/volumekey.c index bcd8349a..7df62267 100644 --- a/lib/volumekey.c +++ b/lib/volumekey.c @@ -243,14 +243,14 @@ bool crypt_volume_key_is_set(const struct volume_key *vk) return vk && vk->key; } -bool crypt_volume_key_upload_kernel_key(struct volume_key *vk) +bool crypt_volume_key_upload_kernel_key(struct volume_key *vk, key_serial_t keyring) { key_serial_t kid; assert(vk && vk->key && vk->key_description && vk->keyring_key_type != INVALID_KEY); - kid = keyring_add_key_in_thread_keyring(vk->keyring_key_type, vk->key_description, - vk->key, vk->keylength); + kid = keyring_add_key_to_keyring(vk->keyring_key_type, vk->key_description, vk->key, + vk->keylength, keyring); if (kid >= 0) { vk->key_id = kid; return true; @@ -265,9 +265,7 @@ void crypt_volume_key_drop_kernel_key(struct crypt_device *cd, struct volume_key assert(vk->key_description || vk->keyring_key_type == INVALID_KEY); assert(!vk->key_description || vk->keyring_key_type != INVALID_KEY); - crypt_unlink_key_by_description_from_thread_keyring(cd, - vk->key_description, - vk->keyring_key_type); + crypt_unlink_key_by_description_from_keyring(cd, vk->key_description, vk->keyring_key_type); } void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct volume_key *vk) @@ -277,6 +275,6 @@ void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct v if (vk->key_id < 0) return; - crypt_unlink_key_from_thread_keyring(cd, vk->key_id); + crypt_unlink_key_from_keyring(cd, vk->key_id); vk->key_id = -1; } -- 2.54.0 ++++++ cryptsetup-Use-unique-intermediary-keyring-name-per-device.patch ++++++ >From 04ef07a7070fc8f71dc8da57d6cc23423e1b632e Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Fri, 19 Jun 2026 16:45:49 +0200 Subject: [PATCH] Use unique intermediary keyring name per device. Replace the static "cryptsetup-keyring" name with "cryptsetup-<uuid_prefix>-<random>" to avoid collisions when multiple LUKS devices are opened by the same process. Fixes: #993. Co-Authored-By: Claude Opus 4.6 <[email protected]> diff --git a/lib/setup.c b/lib/setup.c index 4b051e57..1c0f21e6 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -7673,6 +7673,9 @@ int crypt_volume_key_keyring(struct crypt_device *cd __attribute__((unused)), in int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk) { key_serial_t keyring_id; + char *keyring_description; + char rnd[4]; + const char *uuid; if (!vk || !cd) return -EINVAL; @@ -7683,20 +7686,28 @@ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key } if (!cd->keyring_description) { - cd->keyring_description = strdup("cryptsetup-keyring"); - if (!cd->keyring_description) + uuid = crypt_get_uuid(cd); + if (!uuid) + return -EINVAL; + + if (crypt_random_get(cd, rnd, sizeof(rnd), CRYPT_RND_NORMAL) < 0) + return -EINVAL; + + if (asprintf(&keyring_description, "cryptsetup-%.8s-%02x%02x%02x%02x", + uuid, (unsigned char)rnd[0], (unsigned char)rnd[1], + (unsigned char)rnd[2], (unsigned char)rnd[3]) < 0) return -ENOMEM; - log_dbg(cd, "Loading key (type keyring, name %s) in thread keyring.", cd->keyring_description); - keyring_id = keyring_add_key_in_thread_keyring(KEYRING_KEY, cd->keyring_description, NULL, 0); + log_dbg(cd, "Loading key (type keyring, name %s) in thread keyring.", keyring_description); + keyring_id = keyring_add_key_in_thread_keyring(KEYRING_KEY, keyring_description, NULL, 0); if (keyring_id < 0) { - free(CONST_CAST(void*)cd->keyring_description); - cd->keyring_description = NULL; + free(keyring_description); log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)", errno); log_err(cd, _("Failed to load key in kernel keyring.")); return -EINVAL; } cd->keyring_id = keyring_id; + cd->keyring_description = keyring_description; } log_dbg(cd, "Loading key (type logon, name %s) in %s keyring.", -- 2.54.0 ++++++ cryptsetup-tests-refactor-keyring-helpers.patch ++++++ >From bfcb0c38eb95c08852c7dcd488c28e26c7775cf0 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Fri, 26 Jun 2026 16:26:45 +0200 Subject: [PATCH] tests: refactor keyring helpers. diff --git a/tests/api-test-2.c b/tests/api-test-2.c index c41eb4dc..3ef0adca 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -477,25 +477,27 @@ static key_serial_t add_key_set_perm(const char *type, const char *description, return l == 0 ? kid : -EINVAL; } -static key_serial_t _kernel_key_by_segment_and_type(struct crypt_device *_cd, int segment, - const char* type) +static key_serial_t _kernel_key_by_segment_uuid_and_type(const char *uuid, int segment, + const char *type) + { char key_description[1024]; - if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-d%u", crypt_get_uuid(_cd), segment) < 1) + if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-d%u", uuid, segment) < 1) return -1; return request_key(type, key_description, NULL, 0); } -static key_serial_t _kernel_key_by_segment(struct crypt_device *_cd, int segment) +static key_serial_t _kernel_key_by_segment_and_type(struct crypt_device *_cd, int segment, + const char* type) { - return _kernel_key_by_segment_and_type(_cd, segment, "logon"); + return _kernel_key_by_segment_uuid_and_type(crypt_get_uuid(_cd), segment, type); } static int _volume_key_in_keyring(struct crypt_device *_cd, int segment) { - return _kernel_key_by_segment(_cd, segment) >= 0 ? 0 : -1; + return _kernel_key_by_segment_and_type(_cd, segment, "logon") >= 0 ? 0 : -1; } static int _drop_keyring_key_from_keyring_name(const char *key_description, key_serial_t keyring, const char* type) -- 2.54.0 ++++++ cryptsetup-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch ++++++ >From bb5e8e9f0b34fb8135e948ce60d956c2af7d5c8d Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Fri, 19 Jun 2026 14:58:46 +0200 Subject: [PATCH] tests: revoke keys instead unlinking from thread keyring. With the intermediary thread keyring we can not simply unlink key from thread keyring. Let's make it simple and invalidate the key instead. diff --git a/tests/api-test-2.c b/tests/api-test-2.c index 0523e11d..c41eb4dc 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -427,6 +427,11 @@ static key_serial_t keyctl_unlink(key_serial_t key, key_serial_t keyring) return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring); } +static key_serial_t keyctl_revoke(key_serial_t key) +{ + return syscall(__NR_keyctl, KEYCTL_REVOKE, key); +} + static key_serial_t keyctl_link(key_serial_t key, key_serial_t keyring) { return syscall(__NR_keyctl, KEYCTL_LINK, key, keyring); @@ -504,20 +509,14 @@ static int _drop_keyring_key_from_keyring_name(const char *key_description, key_ return keyctl_unlink(kid, keyring); } -static int _drop_keyring_key_from_keyring_type(struct crypt_device *_cd, int segment, - key_serial_t keyring, const char* type) +static int _revoke_keyring_key(struct crypt_device *_cd, int segment) { - key_serial_t kid = _kernel_key_by_segment_and_type(_cd, segment, type); + key_serial_t kid = _kernel_key_by_segment_and_type(_cd, segment, "logon"); if (kid < 0) return -1; - return keyctl_unlink(kid, keyring); -} - -static int _drop_keyring_key(struct crypt_device *_cd, int segment) -{ - return _drop_keyring_key_from_keyring_type(_cd, segment, KEY_SPEC_THREAD_KEYRING, "logon"); + return keyctl_revoke(kid); } #endif @@ -690,11 +689,11 @@ static void UseLuks2Device(void) // repeat previous tests and check kernel keyring is released when not needed if (t_dm_crypt_keyring_support()) { OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); - FAIL_(_drop_keyring_key(cd, 0), ""); + FAIL_(_revoke_keyring_key(cd, 0), ""); OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), CRYPT_ACTIVATE_KEYRING_KEY)); - OK_(_drop_keyring_key(cd, 0)); + OK_(_revoke_keyring_key(cd, 0)); OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); - OK_(_drop_keyring_key(cd, 0)); + OK_(_revoke_keyring_key(cd, 0)); FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0), "already open"); FAIL_(_volume_key_in_keyring(cd, 0), ""); OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); @@ -704,11 +703,11 @@ static void UseLuks2Device(void) if (!_fips_mode) { /* keyslot 0 is PBKDF2, keyslot 1 is Argon2id */ EQ_(crypt_activate_by_passphrase(cd, NULL, 1, KEY2, strlen(KEY2), 0), 1); - FAIL_(_drop_keyring_key(cd, 0), ""); + FAIL_(_revoke_keyring_key(cd, 0), ""); EQ_(crypt_activate_by_passphrase(cd, NULL, 1, KEY2, strlen(KEY2), CRYPT_ACTIVATE_KEYRING_KEY), 1); - OK_(_drop_keyring_key(cd, 0)); + OK_(_revoke_keyring_key(cd, 0)); EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 1, KEY2, strlen(KEY2), 0), 1); - OK_(_drop_keyring_key(cd, 0)); + OK_(_revoke_keyring_key(cd, 0)); FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, 1, KEY2, strlen(KEY2), 0), "already open"); FAIL_(_volume_key_in_keyring(cd, 0), ""); EQ_(crypt_activate_by_passphrase(cd, NULL, 1, KEY2, strlen(KEY2), 0), 1); @@ -1828,9 +1827,9 @@ static void ResizeDeviceLuks2(void) OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); // erase volume key from kernel keyring if (t_dm_crypt_keyring_support()) - OK_(_drop_keyring_key(cd, 0)); + OK_(_revoke_keyring_key(cd, 0)); else - FAIL_(_drop_keyring_key(cd, 0), "key not found"); + FAIL_(_revoke_keyring_key(cd, 0), "key not found"); // same size is ok OK_(crypt_resize(cd, CDEVICE_1, 0)); // kernel fails to find the volume key in keyring -- 2.54.0 ++++++ cryptsetup-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch ++++++ >From aa214c098a11297f1669fd4d30d2b9c98cbd365e Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Wed, 24 Jun 2026 11:21:27 +0200 Subject: [PATCH] tests: verify VK and internal keyring cleanup after process exit. Check that both the intermediary keyring and the volume key logon key are removed from the kernel keyring after the cryptsetup process exits. Verify via search in /proc/keys. Co-Authored-By: Claude Opus 4.6 <[email protected]> Index: cryptsetup-2.8.6/tests/compat-test2 =================================================================== --- cryptsetup-2.8.6.orig/tests/compat-test2 +++ cryptsetup-2.8.6/tests/compat-test2 @@ -485,6 +485,26 @@ test_reencrypt_vk_link_and_reactivate() echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-keyring "$KEY_DESC" --volume-key-keyring "$KEY_DESC2" > /dev/null 2>&1 && fail } + +# $1 substring to search for in /proc/keys +wait_key_dissapeared() +{ + local ret= + local tries=50 + + grep -q $1 /proc/keys + ret=$? + + while [ $ret -eq 0 -a $tries -gt 0 ]; do + sleep .1 + grep -q $1 /proc/keys + ret=$? + tries=$((tries-1)) + done + + test $ret -ne 0 +} + expect_run() { export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" @@ -1714,5 +1734,20 @@ if ! fips_mode -a -d $LUKS2_LOCKING_DIR; test -f $LUKS2_LOCKING_DIR/$MEMORY_HARD_LOCK_FILE && fail "The --serialize-memory-hard-pbkdf option did not remove the locking file (did not use the file)." fi +if dm_crypt_keyring_support && dm_crypt_keyring_new_kernel; then + prepare "[54] Intermediary keyring VK cleanup" wipe + echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail + UUID=$($CRYPTSETUP luksUUID $LOOPDEV) + + echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME || fail + $CRYPTSETUP -q status $DEV_NAME | grep "key location:" | grep -q "keyring" || fail + + # after cryptsetup open exits both the intermediary keyring and VK logon key must be gone + wait_key_dissapeared "keyring.*cryptsetup-${UUID:0:8}" || fail "Intermediary keyring persists in /proc/keys after process exit" + wait_key_dissapeared "logon.*cryptsetup:${UUID}" || fail "VK logon key persists in /proc/keys after process exit" + + $CRYPTSETUP close $DEV_NAME || fail +fi + remove_mapping exit 0 ++++++ cryptsetup-tests-verify-intermediary-keyring-cleanup-after-cryp.patch ++++++ >From e6573494f0feee971c8079d2697a2d925c3799a0 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina <[email protected]> Date: Thu, 25 Jun 2026 15:35:07 +0200 Subject: [PATCH] tests: verify intermediary keyring cleanup after crypt_free(). Add API-level test that checks both the intermediary keyring and VK logon key are unlinked from the thread keyring after crypt_free(). Unlike the compat-test2 checks (which verify after process exit), this runs in-process where the thread keyring is still alive. Co-Authored-By: Claude Opus 4.6 <[email protected]> diff --git a/tests/api-test-2.c b/tests/api-test-2.c index 3ef0adca..a6b82d18 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -520,6 +520,36 @@ static int _revoke_keyring_key(struct crypt_device *_cd, int segment) return keyctl_revoke(kid); } + +static long keyctl_describe(key_serial_t id, char *buffer, size_t buflen) +{ + return syscall(__NR_keyctl, KEYCTL_DESCRIBE, id, buffer, buflen); +} + +static int _intermediary_keyring_in_thread_keyring(const char *uuid) +{ + key_serial_t keys[64]; + char rdesc[256], prefix[20]; + long r; + int i, count; + + r = snprintf(prefix, sizeof(prefix), "cryptsetup-%.8s", uuid); + if (r < 0 || (size_t)r > sizeof(prefix) - 1) + return -1; + + r = keyctl_read(KEY_SPEC_THREAD_KEYRING, (char *)keys, sizeof(keys)); + if (r < 0) + return -1; + + count = r / sizeof(key_serial_t); + for (i = 0; i < count; i++) { + r = keyctl_describe(keys[i], rdesc, sizeof(rdesc)); + if (r > 0 && (size_t)r <= sizeof(rdesc) && strstr(rdesc, prefix)) + return 0; + } + + return -1; +} #endif static void _cleanup(void) @@ -736,8 +766,26 @@ static void UseLuks2Device(void) key[1] = ~key[1]; FAIL_(crypt_volume_key_verify(cd, key, key_size), "key mismatch"); FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "key mismatch"); + CRYPT_FREE(cd); +#if KERNEL_KEYRING + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + if (t_dm_crypt_keyring_support()) { + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + OK_(_intermediary_keyring_in_thread_keyring(DEVICE_1_UUID)); + OK_(_volume_key_in_keyring(cd, 0)); + } + // All keys uploaded via current device context must be freed. CRYPT_FREE(cd); + if (t_dm_crypt_keyring_support()) { + FAIL_(_intermediary_keyring_in_thread_keyring(DEVICE_1_UUID), "intermediary keyring not cleaned up"); + FAIL_(_kernel_key_by_segment_uuid_and_type(DEVICE_1_UUID, 0, "logon"), "VK not cleaned up"); + } + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + CRYPT_FREE(cd); +#endif } static void SuspendDevice(void) -- 2.54.0
