Skip to content

Commit 479e585

Browse files
coibyakpm00
authored andcommitted
crash_dump: store dm crypt keys in kdump reserved memory
When the kdump kernel image and initrd are loaded, the dm crypts keys will be read from keyring and then stored in kdump reserved memory. Assume a key won't exceed 256 bytes thus MAX_KEY_SIZE=256 according to "cryptsetup benchmark". Link: https://lkml.kernel.org/r/20250502011246.99238-4-coxu@redhat.com Signed-off-by: Coiby Xu <coxu@redhat.com> Acked-by: Baoquan He <bhe@redhat.com> Cc: "Daniel P. Berrange" <berrange@redhat.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Dave Young <dyoung@redhat.com> Cc: Jan Pazdziora <jpazdziora@redhat.com> Cc: Liu Pingfan <kernelfans@gmail.com> Cc: Milan Broz <gmazyland@gmail.com> Cc: Ondrej Kozina <okozina@redhat.com> Cc: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 180cf31 commit 479e585

3 files changed

Lines changed: 142 additions & 1 deletion

File tree

include/linux/crash_core.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ static inline void arch_kexec_protect_crashkres(void) { }
3434
static inline void arch_kexec_unprotect_crashkres(void) { }
3535
#endif
3636

37-
37+
#ifdef CONFIG_CRASH_DM_CRYPT
38+
int crash_load_dm_crypt_keys(struct kimage *image);
39+
#else
40+
static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
41+
#endif
3842

3943
#ifndef arch_crash_handle_hotplug_event
4044
static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { }

include/linux/kexec.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,10 @@ struct kimage {
405405
void *elf_headers;
406406
unsigned long elf_headers_sz;
407407
unsigned long elf_load_addr;
408+
409+
/* dm crypt keys buffer */
410+
unsigned long dm_crypt_keys_addr;
411+
unsigned long dm_crypt_keys_sz;
408412
};
409413

410414
/* kexec interface functions */

kernel/crash_dump_dm_crypt.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,62 @@
11
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <linux/key.h>
3+
#include <linux/keyctl.h>
24
#include <keys/user-type.h>
35
#include <linux/crash_dump.h>
46
#include <linux/configfs.h>
57
#include <linux/module.h>
68

79
#define KEY_NUM_MAX 128 /* maximum dm crypt keys */
10+
#define KEY_SIZE_MAX 256 /* maximum dm crypt key size */
811
#define KEY_DESC_MAX_LEN 128 /* maximum dm crypt key description size */
912

1013
static unsigned int key_count;
1114

15+
struct dm_crypt_key {
16+
unsigned int key_size;
17+
char key_desc[KEY_DESC_MAX_LEN];
18+
u8 data[KEY_SIZE_MAX];
19+
};
20+
21+
static struct keys_header {
22+
unsigned int total_keys;
23+
struct dm_crypt_key keys[] __counted_by(total_keys);
24+
} *keys_header;
25+
26+
static size_t get_keys_header_size(size_t total_keys)
27+
{
28+
return struct_size(keys_header, keys, total_keys);
29+
}
30+
31+
static int read_key_from_user_keying(struct dm_crypt_key *dm_key)
32+
{
33+
const struct user_key_payload *ukp;
34+
struct key *key;
35+
36+
kexec_dprintk("Requesting logon key %s", dm_key->key_desc);
37+
key = request_key(&key_type_logon, dm_key->key_desc, NULL);
38+
39+
if (IS_ERR(key)) {
40+
pr_warn("No such logon key %s\n", dm_key->key_desc);
41+
return PTR_ERR(key);
42+
}
43+
44+
ukp = user_key_payload_locked(key);
45+
if (!ukp)
46+
return -EKEYREVOKED;
47+
48+
if (ukp->datalen > KEY_SIZE_MAX) {
49+
pr_err("Key size %u exceeds maximum (%u)\n", ukp->datalen, KEY_SIZE_MAX);
50+
return -EINVAL;
51+
}
52+
53+
memcpy(dm_key->data, ukp->data, ukp->datalen);
54+
dm_key->key_size = ukp->datalen;
55+
kexec_dprintk("Get dm crypt key (size=%u) %s: %8ph\n", dm_key->key_size,
56+
dm_key->key_desc, dm_key->data);
57+
return 0;
58+
}
59+
1260
struct config_key {
1361
struct config_item item;
1462
const char *description;
@@ -130,6 +178,91 @@ static struct configfs_subsystem config_keys_subsys = {
130178
},
131179
};
132180

181+
static int build_keys_header(void)
182+
{
183+
struct config_item *item = NULL;
184+
struct config_key *key;
185+
int i, r;
186+
187+
if (keys_header != NULL)
188+
kvfree(keys_header);
189+
190+
keys_header = kzalloc(get_keys_header_size(key_count), GFP_KERNEL);
191+
if (!keys_header)
192+
return -ENOMEM;
193+
194+
keys_header->total_keys = key_count;
195+
196+
i = 0;
197+
list_for_each_entry(item, &config_keys_subsys.su_group.cg_children,
198+
ci_entry) {
199+
if (item->ci_type != &config_key_type)
200+
continue;
201+
202+
key = to_config_key(item);
203+
204+
if (!key->description) {
205+
pr_warn("No key description for key %s\n", item->ci_name);
206+
return -EINVAL;
207+
}
208+
209+
strscpy(keys_header->keys[i].key_desc, key->description,
210+
KEY_DESC_MAX_LEN);
211+
r = read_key_from_user_keying(&keys_header->keys[i]);
212+
if (r != 0) {
213+
kexec_dprintk("Failed to read key %s\n",
214+
keys_header->keys[i].key_desc);
215+
return r;
216+
}
217+
i++;
218+
kexec_dprintk("Found key: %s\n", item->ci_name);
219+
}
220+
221+
return 0;
222+
}
223+
224+
int crash_load_dm_crypt_keys(struct kimage *image)
225+
{
226+
struct kexec_buf kbuf = {
227+
.image = image,
228+
.buf_min = 0,
229+
.buf_max = ULONG_MAX,
230+
.top_down = false,
231+
.random = true,
232+
};
233+
int r;
234+
235+
236+
if (key_count <= 0) {
237+
kexec_dprintk("No dm-crypt keys\n");
238+
return -ENOENT;
239+
}
240+
241+
image->dm_crypt_keys_addr = 0;
242+
r = build_keys_header();
243+
if (r)
244+
return r;
245+
246+
kbuf.buffer = keys_header;
247+
kbuf.bufsz = get_keys_header_size(key_count);
248+
249+
kbuf.memsz = kbuf.bufsz;
250+
kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
251+
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
252+
r = kexec_add_buffer(&kbuf);
253+
if (r) {
254+
kvfree((void *)kbuf.buffer);
255+
return r;
256+
}
257+
image->dm_crypt_keys_addr = kbuf.mem;
258+
image->dm_crypt_keys_sz = kbuf.bufsz;
259+
kexec_dprintk(
260+
"Loaded dm crypt keys to kexec_buffer bufsz=0x%lx memsz=0x%lx\n",
261+
kbuf.bufsz, kbuf.memsz);
262+
263+
return r;
264+
}
265+
133266
static int __init configfs_dmcrypt_keys_init(void)
134267
{
135268
int ret;

0 commit comments

Comments
 (0)