[PATCH v2 05/13] security/keys: wipe key payloads before kdump

From: Jan Sebastian Götte

Date: Tue Aug 11 2026 - 14:26:01 EST


When CONFIG_CRASH_WIPE_SECRETS is set, try to erase key payloads on
panic before jumping to the kdump kernel.

CRASH_WIPE_SECRETS notifiers run during panic() with other CPUs stopped
and preemption disabled. In this state, we can't rely on free()'ing
being safe, so we define a new `wipe` key op.

Signed-off-by: Jan Sebastian Götte <linux@xxxxxxxx>
---
Documentation/security/keys/core.rst | 13 +++++++++++
include/linux/key-type.h | 9 ++++++++
security/keys/key.c | 43 ++++++++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+)

diff --git a/Documentation/security/keys/core.rst b/Documentation/security/keys/core.rst
index 326b8a973828..35cb00a87c46 100644
--- a/Documentation/security/keys/core.rst
+++ b/Documentation/security/keys/core.rst
@@ -1596,6 +1596,19 @@ The structure has a number of fields, some of which are mandatory:
It is not safe to sleep in this method; the caller may hold spinlocks.


+ * ``void (*wipe)(struct key *key);``
+
+ This method is optional. It is called from the panic path when
+ CONFIG_CRASH_WIPE_SECRETS is enabled, to erase the key material from
+ memory before the kdump kernel is started, so that it does not end up in
+ the crash dump. Unlike destroy(), it must only clear the payload, not
+ free it.
+
+ This method is called with all other CPUs stopped and preemption
+ disabled, and only for positively instantiated keys. It must not sleep,
+ allocate, free or take locks, as they will never be released.
+
+
* ``void (*describe)(const struct key *key, struct seq_file *p);``

This method is optional. It is called during /proc/keys reading to
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index bb97bd3e5af4..21e07db0c5f2 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -122,6 +122,15 @@ struct key_type {
/* clear the data from a key (optional) */
void (*destroy)(struct key *key);

+ /* wipe the key material without free'ing (optional)
+ * - used from CONFIG_CRASH_WIPE_SECRETS during panic to keep keys out
+ * of crash dumps
+ * - called from the panic path with other CPUs stopped and preemption
+ * disabled
+ * - must not sleep, allocate, free or take locks
+ */
+ void (*wipe)(struct key *key);
+
/* describe a key */
void (*describe)(const struct key *key, struct seq_file *p);

diff --git a/security/keys/key.c b/security/keys/key.c
index b34a64d81d47..213e6f1d5d83 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/workqueue.h>
+#include <linux/crash_core.h>
#include <linux/random.h>
#include <linux/err.h>
#include "internal.h"
@@ -1268,6 +1269,47 @@ void unregister_key_type(struct key_type *ktype)
}
EXPORT_SYMBOL(unregister_key_type);

+/* Called far into vpanic from crash_core.c with other CPUs stopped and
+ * preemption disabled
+ */
+static int key_crash_wipe(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct rb_node *node;
+
+ /* If we can't acquire the lock, the rbtree might be in an inconsistent
+ * state. That's all we can do then, as there's no point to waiting
+ * at this stage.
+ */
+ if (!spin_trylock(&key_serial_lock)) {
+ pr_crit("crash_wipe_secrets: can't acquire key_serial_lock. skipping keyrings.\n");
+ return NOTIFY_DONE;
+ }
+
+ for (node = rb_first(&key_serial_tree); node; node = rb_next(node)) {
+ struct key *key = rb_entry(node, struct key, serial_node);
+
+ /* Negatively instantiated keys have key->state < 0 and never
+ * had a payload attached, so only wipe positive ones.
+ */
+ if (key->type == &key_type_keyring || !key_is_positive(key))
+ continue;
+
+ /* We have a dedicated wipe callback for this since free'ing
+ * isn't safe at this point
+ */
+ if (key->type->wipe)
+ key->type->wipe(key);
+ }
+ spin_unlock(&key_serial_lock);
+ /* off to kexec()! */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block key_crash_wipe_nb = {
+ .notifier_call = key_crash_wipe
+};
+
/*
* Initialise the key management state.
*/
@@ -1290,4 +1332,5 @@ void __init key_init(void)

rb_insert_color(&root_key_user.node,
&key_user_tree);
+ crash_wipe_secrets_register(&key_crash_wipe_nb);
}

--
2.53.0