lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20260116103347.523747-1-coxu@redhat.com>
Date: Fri, 16 Jan 2026 18:33:46 +0800
From: Coiby Xu <coxu@...hat.com>
To: kexec@...ts.infradead.org
Cc: Philipp Rudo <prudo@...hat.com>,
	Heiko Carstens <hca@...ux.ibm.com>,
	Vasily Gorbik <gor@...ux.ibm.com>,
	Alexander Gordeev <agordeev@...ux.ibm.com>,
	Christian Borntraeger <borntraeger@...ux.ibm.com>,
	Sven Schnelle <svens@...ux.ibm.com>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Baoquan He <bhe@...hat.com>,
	Vivek Goyal <vgoyal@...hat.com>,
	Dave Young <dyoung@...hat.com>,
	linux-s390@...r.kernel.org (open list:S390 ARCHITECTURE),
	linux-kernel@...r.kernel.org (open list)
Subject: [RFC] s390x/kdump: pass dm-crypt keys to kdump kernel

CONFIG_CRASH_DM_CRYPT has been introduced to support LUKS-encrypted
device dump target by addressing two challenges [1][2],
 - Kdump kernel may not be able to decrypt the LUKS partition. For some
   machines, a system administrator may not have a chance to enter the
   password to decrypt the device in kdump initramfs after the 1st kernel
   crashes

 - LUKS2 by default use the memory-hard Argon2 key derivation function
   which is quite memory-consuming compared to the limited memory reserved
   for kdump.

To also enable this feature for s390X, we only need to build up the
kernel command parameter dmcryptkeys=<addr> to pass the memory address
of the stored info of dm-crypt keys to kdump kernel. Unlike other
architectures e.g. x86_64, the memory storing the dm-crypt keys won't be
reserved automatically. So also pass the dmcryptkeys_size kernel
parameter to kdump kernel so the memory can be reserved.

Since dm-crypt keys are sensitive data, it will be more secure to place
them in a random way. However the only two ways I can find so far is to
put the keys inside the following two regions,
  1. [crashk_res.start + SZ_64M, crashk_res.start + SZ_64M + SZ_32M]
  2. [data->memsz + SZ_64M, data->memsz + SZ_64M + SZ_4M]

Placing the keys in other regions randomly as bellow can crash the KVM
machine immediately after triggering a kernel panic,

    [data->memsz, data->memsz + SZ_4M]
    [crashk_res.end - SZ_32M, crashk_res.end]

And calling kexec_add_buffer/ipl_report_add_component after loading
kernel image and initramfs doesn't help either.

So obviously I miss something about how
kexec_add_buffer/ipl_report_add_component work in S390. Any advice will
be appreciated! Thanks!

[1] https://lore.kernel.org/all/20250502011246.99238-8-coxu@redhat.com/T/#u
[2] "Write the dump file to encrypted disk volume", Documentation/admin-guide/kdump/kdump.rst

Signed-off-by: Coiby Xu <coxu@...hat.com>
---
 arch/s390/kernel/crash_dump.c         |  9 ++++
 arch/s390/kernel/machine_kexec_file.c | 68 +++++++++++++++++++++++++--
 kernel/crash_dump_dm_crypt.c          | 54 +++++++++++++++------
 3 files changed, 114 insertions(+), 17 deletions(-)

diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index d4839de8ce9d..d941d640c541 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -705,3 +705,12 @@ ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
 	*ppos += count;
 	return count;
 }
+
+ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos)
+{
+	void *src = __va((phys_addr_t)dm_crypt_keys_addr);
+
+	memcpy(buf, src, count);
+	*ppos += count;
+	return count;
+}
diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
index a36d7311c668..b881817aad2f 100644
--- a/arch/s390/kernel/machine_kexec_file.c
+++ b/arch/s390/kernel/machine_kexec_file.c
@@ -239,6 +239,65 @@ static int kexec_file_add_ipl_report(struct kimage *image,
 	return ret;
 }
 
+#ifdef CONFIG_CRASH_DUMP
+static int setup_crash_dmcrypt(struct kimage *image, struct s390_load_data *data,
+			       unsigned long max_command_line_size)
+{
+	struct kexec_buf kexec_buf = { .random = true };
+	unsigned long temp_start, temp_end;
+	size_t cmd_buf_len;
+	char *cmd_buf;
+	int ret;
+
+	ret = crash_load_dm_crypt_keys(image);
+	if (ret == -ENOENT) {
+		kexec_dprintk("No dm crypt key to load\n");
+		return 0;
+	} else if (ret) {
+		pr_err("Failed to load dm crypt keys\n");
+		return -EINVAL;
+	}
+
+	kexec_buf.image = image;
+	kexec_buf.buffer = (void *)image->dm_crypt_keys_addr;
+	kexec_buf.bufsz = image->dm_crypt_keys_sz;
+	kexec_buf.memsz = kexec_buf.bufsz;
+
+	// Place dm-crypt keys randomly above crashk_res.start+SZ_64M
+	temp_start = crashk_res.start + SZ_64M;
+	temp_end = temp_start + SZ_32M;
+	kexec_random_range_start(temp_start, temp_end, &kexec_buf, &temp_start);
+	kexec_buf.mem = ALIGN_DOWN(temp_start, PAGE_SIZE);
+	ret = kexec_add_buffer(&kexec_buf);
+	if (ret)
+		return ret;
+
+	data->memsz = kexec_buf.mem - crashk_res.start;
+	data->memsz += kexec_buf.memsz;
+	ret = ipl_report_add_component(data->report, &kexec_buf, 0, 0);
+	if (ret)
+		return ret;
+
+	image->dm_crypt_keys_addr = kexec_buf.mem;
+	cmd_buf = kasprintf(GFP_KERNEL,
+			    "%s dmcryptkeys=0x%llx dmcryptkeys_size=%lu",
+			    image->cmdline_buf,
+			    kexec_buf.mem - crashk_res.start,
+			    image->dm_crypt_keys_sz);
+	cmd_buf_len = strlen(cmd_buf) + 1;
+
+	if (cmd_buf_len > max_command_line_size) {
+		kfree(cmd_buf);
+		return -ENOMEM;
+	}
+
+	kfree(image->cmdline_buf);
+	image->cmdline_buf_len = cmd_buf_len;
+	image->cmdline_buf = cmd_buf;
+	return 0;
+}
+#endif
+
 void *kexec_file_add_components(struct kimage *image,
 				int (*add_kernel)(struct kimage *image,
 						  struct s390_load_data *data))
@@ -273,9 +332,6 @@ void *kexec_file_add_components(struct kimage *image,
 	if (image->cmdline_buf_len >= max_command_line_size)
 		goto out;
 
-	memcpy(data.parm->command_line, image->cmdline_buf,
-	       image->cmdline_buf_len);
-
 #ifdef CONFIG_CRASH_DUMP
 	if (image->type == KEXEC_TYPE_CRASH) {
 		data.parm->oldmem_base = crashk_res.start;
@@ -293,6 +349,12 @@ void *kexec_file_add_components(struct kimage *image,
 	if (ret)
 		goto out;
 
+	if (setup_crash_dmcrypt(image, &data, max_command_line_size))
+		goto out;
+
+	memcpy(data.parm->command_line, image->cmdline_buf,
+	       image->cmdline_buf_len);
+
 	if (data.kernel_mem == 0) {
 		unsigned long restart_psw =  0x0008000080000000UL;
 		restart_psw += image->start;
diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
index 401423ba477d..67b74d2d0987 100644
--- a/kernel/crash_dump_dm_crypt.c
+++ b/kernel/crash_dump_dm_crypt.c
@@ -5,6 +5,7 @@
 #include <linux/crash_dump.h>
 #include <linux/cc_platform.h>
 #include <linux/configfs.h>
+#include <linux/memblock.h>
 #include <linux/module.h>
 
 #define KEY_NUM_MAX 128	/* maximum dm crypt keys */
@@ -48,6 +49,26 @@ static int __init setup_dmcryptkeys(char *arg)
 
 early_param("dmcryptkeys", setup_dmcryptkeys);
 
+static int __init setup_dmcryptkeys_size(char *arg)
+{
+	size_t keys_size;
+	int ret;
+
+	if (dm_crypt_keys_addr == 0) {
+		pr_warn("dmcryptkeys=0\n");
+		return -EINVAL;
+	}
+
+	if (!arg)
+		return -EINVAL;
+
+	ret = kstrtoul(arg, 0, &keys_size);
+	memblock_reserve((phys_addr_t)dm_crypt_keys_addr, keys_size);
+	return 0;
+}
+
+early_param("dmcryptkeys_size", setup_dmcryptkeys_size);
+
 /*
  * Architectures may override this function to read dm crypt keys
  */
@@ -415,22 +436,27 @@ int crash_load_dm_crypt_keys(struct kimage *image)
 			return r;
 	}
 
-	kbuf.buffer = keys_header;
-	kbuf.bufsz = get_keys_header_size(key_count);
+	if (!IS_ENABLED(CONFIG_S390)) {
+		kbuf.buffer = keys_header;
+		kbuf.bufsz = get_keys_header_size(key_count);
 
-	kbuf.memsz = kbuf.bufsz;
-	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
-	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
-	r = kexec_add_buffer(&kbuf);
-	if (r) {
-		kvfree((void *)kbuf.buffer);
-		return r;
+		kbuf.memsz = kbuf.bufsz;
+		kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		r = kexec_add_buffer(&kbuf);
+		if (r) {
+			kvfree((void *)kbuf.buffer);
+			return r;
+		}
+		image->dm_crypt_keys_addr = kbuf.mem;
+		image->dm_crypt_keys_sz = kbuf.bufsz;
+		kexec_dprintk(
+			"Loaded dm crypt keys to kexec_buffer bufsz=0x%lx memsz=0x%lx\n",
+			kbuf.bufsz, kbuf.memsz);
+	} else {
+		image->dm_crypt_keys_addr = (unsigned long)keys_header;
+		image->dm_crypt_keys_sz = get_keys_header_size(key_count);
 	}
-	image->dm_crypt_keys_addr = kbuf.mem;
-	image->dm_crypt_keys_sz = kbuf.bufsz;
-	kexec_dprintk(
-		"Loaded dm crypt keys to kexec_buffer bufsz=0x%lx memsz=0x%lx\n",
-		kbuf.bufsz, kbuf.memsz);
 
 	return r;
 }

base-commit: 7f98ab9da046865d57c102fd3ca9669a29845f67
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ