From 2bf77a8fa40091a27e186c93515fb165199e5122 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Thu, 30 Jul 2026 16:20:15 +0200 Subject: [PATCH] Load volume keys in an intermediary keyring. Adds patches fixing the pinned thread keyring issue. Reinstate skipped gating tests due to missing crypto-check test utility. - Resolves: RHEL-193183 --- cryptsetup-2.8.7-Add-keyring-key-type.patch | 38 +++ ...-in-intermediary-keyring-linked-in-t.patch | 246 ++++++++++++++++++ ...intermediary-keyring-name-per-device.patch | 68 +++++ ...bug_teardown-helper-in-reencryption-.patch | 58 +++++ ...pto-check-work-in-local-install-test.patch | 96 +++++++ ...2.8.7-tests-refactor-keyring-helpers.patch | 50 ++++ ...s-instead-unlinking-from-thread-keyr.patch | 98 +++++++ ...and-internal-keyring-cleanup-after-p.patch | 51 ++++ ...ermediary-keyring-cleanup-after-cryp.patch | 88 +++++++ cryptsetup.spec | 19 +- 10 files changed, 810 insertions(+), 2 deletions(-) create mode 100644 cryptsetup-2.8.7-Add-keyring-key-type.patch create mode 100644 cryptsetup-2.8.7-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch create mode 100644 cryptsetup-2.8.7-Use-unique-intermediary-keyring-name-per-device.patch create mode 100644 cryptsetup-2.8.7-test-use-scsi_debug_teardown-helper-in-reencryption-.patch create mode 100644 cryptsetup-2.8.7-tests-Make-crypto-check-work-in-local-install-test.patch create mode 100644 cryptsetup-2.8.7-tests-refactor-keyring-helpers.patch create mode 100644 cryptsetup-2.8.7-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch create mode 100644 cryptsetup-2.8.7-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch create mode 100644 cryptsetup-2.8.7-tests-verify-intermediary-keyring-cleanup-after-cryp.patch diff --git a/cryptsetup-2.8.7-Add-keyring-key-type.patch b/cryptsetup-2.8.7-Add-keyring-key-type.patch new file mode 100644 index 0000000..f690aa1 --- /dev/null +++ b/cryptsetup-2.8.7-Add-keyring-key-type.patch @@ -0,0 +1,38 @@ +From b6fb6fc0fdc661afba734f4c29350fa6be2ede8f Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Fri, 19 Jun 2026 16:41:47 +0200 +Subject: [PATCH 01/48] Add keyring key type. + +--- + lib/utils_keyring.c | 1 + + lib/utils_keyring.h | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +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 +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.55.0 + diff --git a/cryptsetup-2.8.7-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch b/cryptsetup-2.8.7-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch new file mode 100644 index 0000000..1d1e010 --- /dev/null +++ b/cryptsetup-2.8.7-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch @@ -0,0 +1,246 @@ +From 413a3dd04ec07ad7c3afaed84561cbc7a42f108f Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Thu, 25 Jun 2026 12:05:53 +0200 +Subject: [PATCH 02/48] 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/20240123-vfs-bdev-file-v2-4-adbd023e19cc@kernel.org/ + +Fixes: #993. +--- + lib/internal.h | 6 ++-- + lib/setup.c | 83 +++++++++++++++++++++++++++++++++++++------------ + lib/volumekey.c | 12 +++---- + 3 files changed, 71 insertions(+), 30 deletions(-) + +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.55.0 + diff --git a/cryptsetup-2.8.7-Use-unique-intermediary-keyring-name-per-device.patch b/cryptsetup-2.8.7-Use-unique-intermediary-keyring-name-per-device.patch new file mode 100644 index 0000000..40e4b7c --- /dev/null +++ b/cryptsetup-2.8.7-Use-unique-intermediary-keyring-name-per-device.patch @@ -0,0 +1,68 @@ +From 04ef07a7070fc8f71dc8da57d6cc23423e1b632e Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Fri, 19 Jun 2026 16:45:49 +0200 +Subject: [PATCH 03/48] Use unique intermediary keyring name per device. + +Replace the static "cryptsetup-keyring" name with +"cryptsetup--" to avoid collisions when +multiple LUKS devices are opened by the same process. + +Fixes: #993. + +Co-Authored-By: Claude Opus 4.6 +--- + lib/setup.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +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.55.0 + diff --git a/cryptsetup-2.8.7-test-use-scsi_debug_teardown-helper-in-reencryption-.patch b/cryptsetup-2.8.7-test-use-scsi_debug_teardown-helper-in-reencryption-.patch new file mode 100644 index 0000000..90cb074 --- /dev/null +++ b/cryptsetup-2.8.7-test-use-scsi_debug_teardown-helper-in-reencryption-.patch @@ -0,0 +1,58 @@ +From 0d49c448f070a09c0fcb12aab525b978da91e559 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Tue, 30 Jun 2026 12:44:44 +0200 +Subject: [PATCH] test: use scsi_debug_teardown helper in reencryption test. + +--- + tests/reencryption-compat-test | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/tests/reencryption-compat-test b/tests/reencryption-compat-test +index a14a5b4d..090373d8 100755 +--- a/tests/reencryption-compat-test ++++ b/tests/reencryption-compat-test +@@ -37,10 +37,19 @@ fips_mode() + [ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ] + } + +-del_scsi_device() +-{ +- rmmod scsi_debug >/dev/null 2>&1 +- sleep 1 ++# $1 path to scsi debug bdev ++scsi_debug_teardown() { ++ local _tries=15; ++ ++ while [ -b "$1" -a $_tries -gt 0 ]; do ++ rmmod scsi_debug >/dev/null 2>&1 ++ if [ -b "$1" ]; then ++ sleep .1 ++ _tries=$((_tries-1)) ++ fi ++ done ++ ++ test ! -b "$1" || rmmod scsi_debug >/dev/null 2>&1 + } + + remove_mapping() +@@ -52,7 +61,7 @@ remove_mapping() + umount $MNT_DIR > /dev/null 2>&1 + rmdir $MNT_DIR > /dev/null 2>&1 + LOOPDEV1="" +- del_scsi_device ++ test -b "$SCSI_DEV" && scsi_debug_teardown $SCSI_DEV + } + + fail() +@@ -90,7 +99,7 @@ valgrind_run() + } + + add_scsi_device() { +- del_scsi_device ++ test -b "$SCSI_DEV" && scsi_debug_teardown $SCSI_DEV + if [ -d /sys/module/scsi_debug ] ; then + echo "Cannot use scsi_debug module (in use or compiled-in), test skipped." + exit 77 +-- +2.55.0 + diff --git a/cryptsetup-2.8.7-tests-Make-crypto-check-work-in-local-install-test.patch b/cryptsetup-2.8.7-tests-Make-crypto-check-work-in-local-install-test.patch new file mode 100644 index 0000000..38ecb44 --- /dev/null +++ b/cryptsetup-2.8.7-tests-Make-crypto-check-work-in-local-install-test.patch @@ -0,0 +1,96 @@ +diff -rupN cryptsetup-2.8.6.old/tests/crypto-check.c cryptsetup-2.8.6/tests/crypto-check.c +--- cryptsetup-2.8.6.old/tests/crypto-check.c 2026-07-31 11:20:10.870518467 +0200 ++++ cryptsetup-2.8.6/tests/crypto-check.c 2026-07-31 11:24:10.808822709 +0200 +@@ -6,10 +6,31 @@ + */ + + #include ++#include + #include ++#include + #include + #include + ++static bool fips_mode(void) ++{ ++ int fd; ++ char buf = 0; ++ ++ fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY); ++ ++ if (fd < 0) ++ return false; ++ ++ if (read(fd, &buf, 1) != 1) ++ buf = '0'; ++ ++ close(fd); ++ ++ return (buf == '1'); ++} ++ ++#ifndef NO_CRYPT_BACKEND + #include "crypto_backend/crypto_backend.h" + + static bool fips_mode(void) +@@ -64,6 +85,33 @@ static int check_hash(const char *hash) + crypt_hash_destroy(h); + return EXIT_SUCCESS; + } ++#else /* NO_CRYPT_BACKEND */ ++static int crypt_backend_init(bool fips_mode __attribute__((unused))) { return 0; }; ++static void crypt_backend_destroy(void) {}; ++static const char *crypt_backend_version(void) { return "none"; }; ++ ++static int check_cipher(const char *alg, const char *mode, unsigned long key_bits) ++{ ++ if (strcmp(alg, "aes")) ++ return EXIT_FAILURE; ++ ++ if (!strcmp(mode, "cbc") && (key_bits == 128 || key_bits == 256)) ++ return EXIT_SUCCESS; ++ ++ if (!strcmp(mode, "xts") && (key_bits == 256 || key_bits == 512)) ++ return EXIT_SUCCESS; ++ ++ return EXIT_FAILURE; ++} ++ ++static int check_hash(const char *hash) ++{ ++ if (!strcmp(hash, "sha512") || !strcmp(hash, "sha256") || !strcmp(hash, "sha1")) ++ return EXIT_SUCCESS; ++ ++ return EXIT_FAILURE; ++} ++#endif + + static void __attribute__((noreturn)) exit_help(bool destroy_backend) + { +diff -rupN cryptsetup-2.8.6.old/tests/Makefile.localtest cryptsetup-2.8.6/tests/Makefile.localtest +--- cryptsetup-2.8.6.old/tests/Makefile.localtest 2026-07-31 11:20:10.844518216 +0200 ++++ cryptsetup-2.8.6/tests/Makefile.localtest 2026-07-31 11:20:37.834945118 +0200 +@@ -4,11 +4,11 @@ + # (append TESTSUITE_NOSKIP=y to avoid treating skipped tests as success) + # + CPPFLAGS=-I../lib/ -I../lib/luks1 -DHAVE_DECL_DM_TASK_RETRY_REMOVE -DKERNEL_KEYRING \ +- -DHAVE_SYS_SYSMACROS_H -DNO_CRYPTSETUP_PATH ++ -DHAVE_SYS_SYSMACROS_H -DNO_CRYPTSETUP_PATH -DNO_CRYPT_BACKEND + CFLAGS=-O2 -g -Wall -D_GNU_SOURCE + LDLIBS=-lcryptsetup -ldevmapper + TESTS=$(wildcard *-test *-test2) api-test api-test-2 all-symbols-test unit-utils-crypt-test +-TESTS_UTILS=differ unit-utils-io unit-wipe ++TESTS_UTILS=differ unit-utils-io unit-wipe crypto-check + + ifneq ($(RUN_SSH_PLUGIN_TEST),) + TESTS += ssh-test-plugin +@@ -24,6 +24,9 @@ check-programs: $(TESTS_UTILS) $(TESTS) + differ: differ.o + $(CC) -o $@ $^ + ++crypto-check: crypto-check.o ++ $(CC) -o $@ $^ ++ + api-test: api-test.o test_utils.o + $(CC) -o $@ $^ $(LDLIBS) + diff --git a/cryptsetup-2.8.7-tests-refactor-keyring-helpers.patch b/cryptsetup-2.8.7-tests-refactor-keyring-helpers.patch new file mode 100644 index 0000000..4aeeae9 --- /dev/null +++ b/cryptsetup-2.8.7-tests-refactor-keyring-helpers.patch @@ -0,0 +1,50 @@ +From bfcb0c38eb95c08852c7dcd488c28e26c7775cf0 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Fri, 26 Jun 2026 16:26:45 +0200 +Subject: [PATCH 06/48] tests: refactor keyring helpers. + +--- + tests/api-test-2.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +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.55.0 + diff --git a/cryptsetup-2.8.7-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch b/cryptsetup-2.8.7-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch new file mode 100644 index 0000000..b70441c --- /dev/null +++ b/cryptsetup-2.8.7-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch @@ -0,0 +1,98 @@ +From bb5e8e9f0b34fb8135e948ce60d956c2af7d5c8d Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Fri, 19 Jun 2026 14:58:46 +0200 +Subject: [PATCH 04/48] 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. +--- + tests/api-test-2.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +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.55.0 + diff --git a/cryptsetup-2.8.7-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch b/cryptsetup-2.8.7-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch new file mode 100644 index 0000000..6c0cbe3 --- /dev/null +++ b/cryptsetup-2.8.7-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch @@ -0,0 +1,51 @@ +diff -rupN cryptsetup-2.8.6.old/tests/compat-test2 cryptsetup-2.8.6/tests/compat-test2 +--- cryptsetup-2.8.6.old/tests/compat-test2 2026-07-30 16:13:34.138738231 +0200 ++++ cryptsetup-2.8.6/tests/compat-test2 2026-07-30 16:15:19.422763720 +0200 +@@ -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 "[53] 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 diff --git a/cryptsetup-2.8.7-tests-verify-intermediary-keyring-cleanup-after-cryp.patch b/cryptsetup-2.8.7-tests-verify-intermediary-keyring-cleanup-after-cryp.patch new file mode 100644 index 0000000..63f1840 --- /dev/null +++ b/cryptsetup-2.8.7-tests-verify-intermediary-keyring-cleanup-after-cryp.patch @@ -0,0 +1,88 @@ +From e6573494f0feee971c8079d2697a2d925c3799a0 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Thu, 25 Jun 2026 15:35:07 +0200 +Subject: [PATCH 07/48] 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 +--- + tests/api-test-2.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +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.55.0 + diff --git a/cryptsetup.spec b/cryptsetup.spec index d8de1c3..6d0b0de 100644 --- a/cryptsetup.spec +++ b/cryptsetup.spec @@ -1,7 +1,7 @@ Summary: Utility for setting up encrypted disks Name: cryptsetup Version: 2.8.6 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ and LGPLv2+ URL: https://gitlab.com/cryptsetup/cryptsetup BuildRequires: autoconf, automake, libtool, gettext-devel, @@ -16,7 +16,7 @@ Obsoletes: %{name}-reencrypt <= %{version} Provides: %{name}-reencrypt = %{version} %global upstream_version %{version} -Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-%{upstream_version}.tar.xz +Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.8/cryptsetup-%{upstream_version}.tar.xz Patch0001: %{name}-Add-FIPS-related-error-message-in-keyslot-add-code.patch Patch0002: %{name}-Enable-to-use-Argon2-in-FIPS-with-openssl-backend.patch @@ -29,6 +29,15 @@ Patch0008: %{name}-2.8.7-reencrypt-better-name-error-values-to-match-the-desc.pa Patch0009: %{name}-2.8.7-reencrypt-refactor-overlay-devices-teardown.patch Patch0010: %{name}-2.8.7-reencrypt-add-more-gracefull-reencryption-error-path.patch Patch0011: %{name}-2.8.7-tests-Add-reencryption-error-path-tests.patch +Patch0012: %{name}-2.8.7-Add-keyring-key-type.patch +Patch0013: %{name}-2.8.7-Load-volume-keys-in-intermediary-keyring-linked-in-t.patch +Patch0014: %{name}-2.8.7-Use-unique-intermediary-keyring-name-per-device.patch +Patch0015: %{name}-2.8.7-tests-revoke-keys-instead-unlinking-from-thread-keyr.patch +Patch0016: %{name}-2.8.7-tests-verify-VK-and-internal-keyring-cleanup-after-p.patch +Patch0017: %{name}-2.8.7-tests-refactor-keyring-helpers.patch +Patch0018: %{name}-2.8.7-tests-verify-intermediary-keyring-cleanup-after-cryp.patch +Patch0019: %{name}-2.8.7-tests-Make-crypto-check-work-in-local-install-test.patch +Patch0020: %{name}-2.8.7-test-use-scsi_debug_teardown-helper-in-reencryption-.patch %description The cryptsetup package contains a utility for setting up @@ -113,6 +122,12 @@ rm -rf %{buildroot}%{_libdir}/*.la %ghost %attr(700, -, -) %dir /run/cryptsetup %changelog +%changelog +* Fri Jul 31 2026 Ondrej Kozina - 2.8.6-2 +- patch: load volume keys in an intermediary keyring linked in the thread keyring. +- patch: reinstate few skipped tests due to missing crypto-check test utility. +- Resolves: 193183 + * Fri May 08 2026 Kristina Hanicova - 2.8.6-1 - Update to cryptsetup 2.8.6. - patch: ci: Replace jq with bash wrapper.