[PATCH v15 09/23] kexec: Fix UAF and Double Free in crash_load_dm_crypt_keys()
From: Jinjie Ruan <hidden>
Date: 2026-06-01 09:49:11
Also in:
kexec, linux-devicetree, linux-doc, linux-riscv, lkml, loongarch
Subsystem:
kdump, the rest · Maintainers:
Andrew Morton, Baoquan He, Mike Rapoport, Pasha Tatashin, Pratyush Yadav, Linus Torvalds
A static memory safety review by Sashiko AI identified a high-severity
Use-After-Free (UAF) and Double Free vulnerability in the dm-crypt keys
handling path during arm64 kexec image placement retry loops.
In crash_load_dm_crypt_keys(), when the segment allocation fails via
kexec_add_buffer(), the error path invokes `kvfree((void *)kbuf.buffer)`
to reclaim the keys buffer. However, the global pointer `keys_header` is
left dangling with a stale address, creating an insecure memory trap.
When the top-level loader image_load() retries the next available placement
hole, crash_load_dm_crypt_keys() is re-entered. Since `is_dm_key_reused`
is a read-only global configuration managed by user-space configfs,
it cannot be mutated by the kernel. If it remains true, the loader skips
build_keys_header() and blindly reuses the stale `keys_header` pointer
for kbuf.buffer, triggering a severe Use-After-Free or a Null pointer
dereference during kexec_add_buffer(). Alternatively, a new headers build
can trigger a recursive Double Free inside build_keys_header().
Fix this by setting the global `keys_header` to NULL immediately after
it is freed in the failure path. Concurrently, upgrade the header
regeneration check to a composite condition:
`if (!is_dm_key_reused || !keys_header)`
This ensures that if a previous retry attempt wiped the buffer, the kernel
will automatically and safely trigger a fresh header regeneration
internally without modifying the user-configured `is_dm_key_reused` state
flag, achieving absolute data consistency and memory safety across all
retry paths.
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Baoquan He <redacted>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Pratyush Yadav <pratyush@kernel.org>
Cc: Dave Young <ruirui.yang@linux.dev>
Cc: stable@vger.kernel.org
Fixes: e3a84be1ec2f ("arm64,ppc64le/kdump: pass dm-crypt keys to kdump kernel")
Signed-off-by: Jinjie Ruan <redacted>
---
kernel/crash_dump_dm_crypt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
index cb875ddb6ba6..2c5462876337 100644
--- a/kernel/crash_dump_dm_crypt.c
+++ b/kernel/crash_dump_dm_crypt.c@@ -412,13 +412,12 @@ int crash_load_dm_crypt_keys(struct kimage *image) }; int r; - if (key_count <= 0) { kexec_dprintk("No dm-crypt keys\n"); return 0; } - if (!is_dm_key_reused) { + if (!is_dm_key_reused || unlikely(!keys_header)) { image->dm_crypt_keys_addr = 0; r = build_keys_header(); if (r) {
@@ -437,6 +436,7 @@ int crash_load_dm_crypt_keys(struct kimage *image) if (r) { pr_err("Failed to call kexec_add_buffer, ret=%d\n", r); kvfree((void *)kbuf.buffer); + keys_header = NULL; return r; } image->dm_crypt_keys_addr = kbuf.mem;
--
2.34.1