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>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240110071522.1308935-4-coxu@redhat.com>
Date: Wed, 10 Jan 2024 15:15:18 +0800
From: Coiby Xu <coxu@...hat.com>
To: kexec@...ts.infradead.org
Cc: Ondrej Kozina <okozina@...hat.com>,
	Milan Broz <gmazyland@...il.com>,
	Thomas Staudt <tstaudt@...ibm.com>,
	Daniel P . Berrangé <berrange@...hat.com>,
	Kairui Song <ryncsn@...il.com>,
	dm-devel@...hat.com,
	Jan Pazdziora <jpazdziora@...hat.com>,
	Pingfan Liu <kernelfans@...il.com>,
	Baoquan He <bhe@...hat.com>,
	Dave Young <dyoung@...hat.com>,
	linux-kernel@...r.kernel.org,
	x86@...nel.org,
	Dave Hansen <dave.hansen@...el.com>,
	Vitaly Kuznetsov <vkuznets@...hat.com>,
	Vivek Goyal <vgoyal@...hat.com>
Subject: [PATCH v2 3/5] crash_dump: retrieve dm crypt key in kdump kernel

Crash kernel will retrieve the dm crypt volume key based on the
dmcryptkey command line parameter. When user space writes the key
description to /sys/kernel/crash_dm_crypt_key, the crash kernel will
save the encryption key to the user keyring. Then user space e.g.
cryptsetup's --volume-key-keyring API can use it to unlock the encrypted
device.

Signed-off-by: Coiby Xu <coxu@...hat.com>
---
 include/linux/crash_dump.h   |   2 +
 kernel/crash_dump_dm_crypt.c | 115 ++++++++++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index acc55626afdc..b44adc3962da 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -15,6 +15,8 @@
 extern unsigned long long elfcorehdr_addr;
 extern unsigned long long elfcorehdr_size;
 
+extern unsigned long long luks_volume_key_addr;
+
 #ifdef CONFIG_CRASH_DUMP
 extern int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size);
 extern void elfcorehdr_free(unsigned long long addr);
diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
index 3a0b0b773598..755017fa5c1b 100644
--- a/kernel/crash_dump_dm_crypt.c
+++ b/kernel/crash_dump_dm_crypt.c
@@ -1,7 +1,82 @@
 // SPDX-License-Identifier: GPL-2.0-only
+#include <linux/key.h>
+#include <linux/keyctl.h>
 #include <keys/user-type.h>
 #include <linux/crash_dump.h>
 
+unsigned long long dm_crypt_key_addr;
+EXPORT_SYMBOL_GPL(dm_crypt_key_addr);
+
+static int __init setup_dmcryptkey(char *arg)
+{
+	char *end;
+
+	if (!arg)
+		return -EINVAL;
+	dm_crypt_key_addr = memparse(arg, &end);
+	if (end > arg)
+		return 0;
+
+	dm_crypt_key_addr = 0;
+	return -EINVAL;
+}
+
+early_param("dmcryptkey", setup_dmcryptkey);
+
+/*
+ * Architectures may override this function to read dm crypt key
+ */
+ssize_t __weak dm_crypt_key_read(char *buf, size_t count, u64 *ppos)
+{
+	struct kvec kvec = { .iov_base = buf, .iov_len = count };
+	struct iov_iter iter;
+
+	iov_iter_kvec(&iter, READ, &kvec, 1, count);
+	return read_from_oldmem(&iter, count, ppos, false);
+}
+
+static int retrive_kdump_dm_crypt_key(u8 *buffer, unsigned int *sz)
+{
+	unsigned int key_size;
+	size_t dm_crypt_keybuf_sz;
+	unsigned int *size_ptr;
+	char *dm_crypt_keybuf;
+	u64 addr;
+	int r;
+
+	if (dm_crypt_key_addr == 0) {
+		pr_debug("dm crypt key memory address inaccessible");
+		return -EINVAL;
+	}
+
+	addr = dm_crypt_key_addr;
+
+	/* Read dm crypt key size */
+	r = dm_crypt_key_read((char *)&key_size, sizeof(unsigned int), &addr);
+
+	if (r < 0)
+		return r;
+
+	pr_debug("Retrieve dm crypt key: size=%u\n", key_size);
+	/* Read in dm cryptrkey */
+	dm_crypt_keybuf_sz = sizeof(unsigned int) + key_size * sizeof(u8);
+	dm_crypt_keybuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+					      get_order(dm_crypt_keybuf_sz));
+	if (!dm_crypt_keybuf)
+		return -ENOMEM;
+
+	addr = dm_crypt_key_addr;
+	r = dm_crypt_key_read((char *)dm_crypt_keybuf, dm_crypt_keybuf_sz, &addr);
+
+	if (r < 0)
+		return r;
+	size_ptr = (unsigned int *)dm_crypt_keybuf;
+	memcpy(buffer, size_ptr + 1, key_size * sizeof(u8));
+	pr_debug("Retrieve dm crypt key (size=%u): %48ph...\n", key_size, buffer);
+	*sz = key_size;
+	return 0;
+}
+
 static u8 *dm_crypt_key;
 static unsigned int dm_crypt_key_size;
 
@@ -23,6 +98,43 @@ static DECLARE_DELAYED_WORK(wipe_dm_crypt_key_work, _wipe_dm_crypt_key);
 
 static unsigned __read_mostly wipe_key_delay = 120; /* 2 mins */
 
+static int retore_dm_crypt_key_to_thread_keyring(const char *key_desc)
+{
+	key_ref_t keyring_ref, key_ref;
+	int ret;
+
+	/* find the target keyring (which must be writable) */
+	keyring_ref = lookup_user_key(KEY_SPEC_USER_KEYRING, 0x01, KEY_NEED_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		pr_alert("Failed to get keyring");
+		return PTR_ERR(keyring_ref);
+	}
+
+	dm_crypt_key = kmalloc(128, GFP_KERNEL);
+	ret = retrive_kdump_dm_crypt_key(dm_crypt_key, &dm_crypt_key_size);
+	if (ret) {
+		kfree(dm_crypt_key);
+		return ret;
+	}
+
+	/* create or update the requested key and add it to the target keyring */
+	key_ref = key_create_or_update(keyring_ref, "user", key_desc,
+				       dm_crypt_key, dm_crypt_key_size,
+				       KEY_USR_ALL, KEY_ALLOC_IN_QUOTA);
+
+	if (!IS_ERR(key_ref)) {
+		ret = key_ref_to_ptr(key_ref)->serial;
+		key_ref_put(key_ref);
+		pr_alert("Success adding key %s", key_desc);
+	} else {
+		ret = PTR_ERR(key_ref);
+		pr_alert("Error when adding key");
+	}
+
+	key_ref_put(keyring_ref);
+	return ret;
+}
+
 static int crash_save_temp_dm_crypt_key(const char *key_desc, size_t count)
 {
 	const struct user_key_payload *ukp;
@@ -60,7 +172,8 @@ int crash_sysfs_dm_crypt_key_write(const char *key_desc, size_t count)
 {
 	if (!is_kdump_kernel())
 		return crash_save_temp_dm_crypt_key(key_desc, count);
-	return -EINVAL;
+	else
+		return retore_dm_crypt_key_to_thread_keyring(key_desc);
 }
 EXPORT_SYMBOL(crash_sysfs_dm_crypt_key_write);
 
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ