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
This commit is contained in:
Ondrej Kozina 2026-07-30 16:20:15 +02:00
parent 07eec2ad5c
commit 2bf77a8fa4
10 changed files with 810 additions and 2 deletions

View File

@ -0,0 +1,38 @@
From b6fb6fc0fdc661afba734f4c29350fa6be2ede8f Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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 <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.55.0

View File

@ -0,0 +1,246 @@
From 413a3dd04ec07ad7c3afaed84561cbc7a42f108f Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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

View File

@ -0,0 +1,68 @@
From 04ef07a7070fc8f71dc8da57d6cc23423e1b632e Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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-<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 <noreply@anthropic.com>
---
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

View File

@ -0,0 +1,58 @@
From 0d49c448f070a09c0fcb12aab525b978da91e559 Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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

View File

@ -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 <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+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)

View File

@ -0,0 +1,50 @@
From bfcb0c38eb95c08852c7dcd488c28e26c7775cf0 Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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

View File

@ -0,0 +1,98 @@
From bb5e8e9f0b34fb8135e948ce60d956c2af7d5c8d Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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

View File

@ -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

View File

@ -0,0 +1,88 @@
From e6573494f0feee971c8079d2697a2d925c3799a0 Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
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 <noreply@anthropic.com>
---
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

View File

@ -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 <okozina@redhat.com> - 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 <khanicov@redhat.com> - 2.8.6-1
- Update to cryptsetup 2.8.6.
- patch: ci: Replace jq with bash wrapper.