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/[email protected] Signed-off-by: Coiby Xu <[email protected]> Acked-by: Baoquan He <[email protected]> Cc: "Daniel P. Berrange" <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Dave Young <[email protected]> Cc: Jan Pazdziora <[email protected]> Cc: Liu Pingfan <[email protected]> Cc: Milan Broz <[email protected]> Cc: Ondrej Kozina <[email protected]> Cc: Vitaly Kuznetsov <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 180cf31 commit 479e585

File tree

3 files changed

+142
-1
lines changed

3 files changed

+142
-1
lines changed

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)