File Index
Files and directories
Sign in
FILE

crash_dump_dm_crypt.c

File preview with syntax highlighting.

linux-6.19.14/kernel/crash_dump_dm_crypt.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <linux/key.h>
  3#include <linux/keyctl.h>
  4#include <keys/user-type.h>
  5#include <linux/crash_dump.h>
  6#include <linux/cc_platform.h>
  7#include <linux/configfs.h>
  8#include <linux/module.h>
  9
 10#define KEY_NUM_MAX 128	/* maximum dm crypt keys */
 11#define KEY_SIZE_MAX 256	/* maximum dm crypt key size */
 12#define KEY_DESC_MAX_LEN 128	/* maximum dm crypt key description size */
 13
 14static unsigned int key_count;
 15
 16struct dm_crypt_key {
 17	unsigned int key_size;
 18	char key_desc[KEY_DESC_MAX_LEN];
 19	u8 data[KEY_SIZE_MAX];
 20};
 21
 22static struct keys_header {
 23	unsigned int total_keys;
 24	struct dm_crypt_key keys[] __counted_by(total_keys);
 25} *keys_header;
 26
 27static size_t get_keys_header_size(size_t total_keys)
 28{
 29	return struct_size(keys_header, keys, total_keys);
 30}
 31
 32unsigned long long dm_crypt_keys_addr;
 33EXPORT_SYMBOL_GPL(dm_crypt_keys_addr);
 34
 35static int __init setup_dmcryptkeys(char *arg)
 36{
 37	char *end;
 38
 39	if (!arg)
 40		return -EINVAL;
 41	dm_crypt_keys_addr = memparse(arg, &end);
 42	if (end > arg)
 43		return 0;
 44
 45	dm_crypt_keys_addr = 0;
 46	return -EINVAL;
 47}
 48
 49early_param("dmcryptkeys", setup_dmcryptkeys);
 50
 51/*
 52 * Architectures may override this function to read dm crypt keys
 53 */
 54ssize_t __weak dm_crypt_keys_read(char *buf, size_t count, u64 *ppos)
 55{
 56	struct kvec kvec = { .iov_base = buf, .iov_len = count };
 57	struct iov_iter iter;
 58
 59	iov_iter_kvec(&iter, READ, &kvec, 1, count);
 60	return read_from_oldmem(&iter, count, ppos, cc_platform_has(CC_ATTR_MEM_ENCRYPT));
 61}
 62
 63static int add_key_to_keyring(struct dm_crypt_key *dm_key,
 64			      key_ref_t keyring_ref)
 65{
 66	key_ref_t key_ref;
 67	int r;
 68
 69	/* create or update the requested key and add it to the target keyring */
 70	key_ref = key_create_or_update(keyring_ref, "user", dm_key->key_desc,
 71				       dm_key->data, dm_key->key_size,
 72				       KEY_USR_ALL, KEY_ALLOC_IN_QUOTA);
 73
 74	if (!IS_ERR(key_ref)) {
 75		r = key_ref_to_ptr(key_ref)->serial;
 76		key_ref_put(key_ref);
 77		kexec_dprintk("Success adding key %s", dm_key->key_desc);
 78	} else {
 79		r = PTR_ERR(key_ref);
 80		kexec_dprintk("Error when adding key");
 81	}
 82
 83	key_ref_put(keyring_ref);
 84	return r;
 85}
 86
 87static void get_keys_from_kdump_reserved_memory(void)
 88{
 89	struct keys_header *keys_header_loaded;
 90
 91	arch_kexec_unprotect_crashkres();
 92
 93	keys_header_loaded = kmap_local_page(pfn_to_page(
 94		kexec_crash_image->dm_crypt_keys_addr >> PAGE_SHIFT));
 95
 96	memcpy(keys_header, keys_header_loaded, get_keys_header_size(key_count));
 97	kunmap_local(keys_header_loaded);
 98	arch_kexec_protect_crashkres();
 99}
100
101static int restore_dm_crypt_keys_to_thread_keyring(void)
102{
103	struct dm_crypt_key *key;
104	size_t keys_header_size;
105	key_ref_t keyring_ref;
106	u64 addr;
107
108	/* find the target keyring (which must be writable) */
109	keyring_ref =
110		lookup_user_key(KEY_SPEC_USER_KEYRING, 0x01, KEY_NEED_WRITE);
111	if (IS_ERR(keyring_ref)) {
112		kexec_dprintk("Failed to get the user keyring\n");
113		return PTR_ERR(keyring_ref);
114	}
115
116	addr = dm_crypt_keys_addr;
117	dm_crypt_keys_read((char *)&key_count, sizeof(key_count), &addr);
118	if (key_count < 0 || key_count > KEY_NUM_MAX) {
119		kexec_dprintk("Failed to read the number of dm-crypt keys\n");
120		return -1;
121	}
122
123	kexec_dprintk("There are %u keys\n", key_count);
124	addr = dm_crypt_keys_addr;
125
126	keys_header_size = get_keys_header_size(key_count);
127	keys_header = kzalloc(keys_header_size, GFP_KERNEL);
128	if (!keys_header)
129		return -ENOMEM;
130
131	dm_crypt_keys_read((char *)keys_header, keys_header_size, &addr);
132
133	for (int i = 0; i < keys_header->total_keys; i++) {
134		key = &keys_header->keys[i];
135		kexec_dprintk("Get key (size=%u)\n", key->key_size);
136		add_key_to_keyring(key, keyring_ref);
137	}
138
139	return 0;
140}
141
142static int read_key_from_user_keying(struct dm_crypt_key *dm_key)
143{
144	const struct user_key_payload *ukp;
145	struct key *key;
146	int ret = 0;
147
148	kexec_dprintk("Requesting logon key %s", dm_key->key_desc);
149	key = request_key(&key_type_logon, dm_key->key_desc, NULL);
150
151	if (IS_ERR(key)) {
152		pr_warn("No such logon key %s\n", dm_key->key_desc);
153		return PTR_ERR(key);
154	}
155
156	down_read(&key->sem);
157	ukp = user_key_payload_locked(key);
158	if (!ukp) {
159		ret = -EKEYREVOKED;
160		goto out;
161	}
162
163	if (ukp->datalen > KEY_SIZE_MAX) {
164		pr_err("Key size %u exceeds maximum (%u)\n", ukp->datalen, KEY_SIZE_MAX);
165		ret = -EINVAL;
166		goto out;
167	}
168
169	memcpy(dm_key->data, ukp->data, ukp->datalen);
170	dm_key->key_size = ukp->datalen;
171	kexec_dprintk("Get dm crypt key (size=%u) %s\n", dm_key->key_size,
172		      dm_key->key_desc);
173
174out:
175	up_read(&key->sem);
176	key_put(key);
177	return ret;
178}
179
180struct config_key {
181	struct config_item item;
182	const char *description;
183};
184
185static inline struct config_key *to_config_key(struct config_item *item)
186{
187	return container_of(item, struct config_key, item);
188}
189
190static ssize_t config_key_description_show(struct config_item *item, char *page)
191{
192	return sprintf(page, "%s\n", to_config_key(item)->description);
193}
194
195static ssize_t config_key_description_store(struct config_item *item,
196					    const char *page, size_t count)
197{
198	struct config_key *config_key = to_config_key(item);
199	size_t len;
200	int ret;
201
202	ret = -EINVAL;
203	len = strcspn(page, "\n");
204
205	if (len > KEY_DESC_MAX_LEN) {
206		pr_err("The key description shouldn't exceed %u characters", KEY_DESC_MAX_LEN);
207		return ret;
208	}
209
210	if (!len)
211		return ret;
212
213	kfree(config_key->description);
214	ret = -ENOMEM;
215	config_key->description = kmemdup_nul(page, len, GFP_KERNEL);
216	if (!config_key->description)
217		return ret;
218
219	return count;
220}
221
222CONFIGFS_ATTR(config_key_, description);
223
224static struct configfs_attribute *config_key_attrs[] = {
225	&config_key_attr_description,
226	NULL,
227};
228
229static void config_key_release(struct config_item *item)
230{
231	kfree(to_config_key(item));
232	key_count--;
233}
234
235static struct configfs_item_operations config_key_item_ops = {
236	.release = config_key_release,
237};
238
239static const struct config_item_type config_key_type = {
240	.ct_item_ops = &config_key_item_ops,
241	.ct_attrs = config_key_attrs,
242	.ct_owner = THIS_MODULE,
243};
244
245static struct config_item *config_keys_make_item(struct config_group *group,
246						 const char *name)
247{
248	struct config_key *config_key;
249
250	if (key_count > KEY_NUM_MAX) {
251		pr_err("Only %u keys at maximum to be created\n", KEY_NUM_MAX);
252		return ERR_PTR(-EINVAL);
253	}
254
255	config_key = kzalloc(sizeof(struct config_key), GFP_KERNEL);
256	if (!config_key)
257		return ERR_PTR(-ENOMEM);
258
259	config_item_init_type_name(&config_key->item, name, &config_key_type);
260
261	key_count++;
262
263	return &config_key->item;
264}
265
266static ssize_t config_keys_count_show(struct config_item *item, char *page)
267{
268	return sprintf(page, "%d\n", key_count);
269}
270
271CONFIGFS_ATTR_RO(config_keys_, count);
272
273static bool is_dm_key_reused;
274
275static ssize_t config_keys_reuse_show(struct config_item *item, char *page)
276{
277	return sprintf(page, "%d\n", is_dm_key_reused);
278}
279
280static ssize_t config_keys_reuse_store(struct config_item *item,
281					   const char *page, size_t count)
282{
283	if (!kexec_crash_image || !kexec_crash_image->dm_crypt_keys_addr) {
284		kexec_dprintk(
285			"dm-crypt keys haven't be saved to crash-reserved memory\n");
286		return -EINVAL;
287	}
288
289	if (kstrtobool(page, &is_dm_key_reused))
290		return -EINVAL;
291
292	if (is_dm_key_reused)
293		get_keys_from_kdump_reserved_memory();
294
295	return count;
296}
297
298CONFIGFS_ATTR(config_keys_, reuse);
299
300static struct configfs_attribute *config_keys_attrs[] = {
301	&config_keys_attr_count,
302	&config_keys_attr_reuse,
303	NULL,
304};
305
306/*
307 * Note that, since no extra work is required on ->drop_item(),
308 * no ->drop_item() is provided.
309 */
310static struct configfs_group_operations config_keys_group_ops = {
311	.make_item = config_keys_make_item,
312};
313
314static const struct config_item_type config_keys_type = {
315	.ct_group_ops = &config_keys_group_ops,
316	.ct_attrs = config_keys_attrs,
317	.ct_owner = THIS_MODULE,
318};
319
320static bool restore;
321
322static ssize_t config_keys_restore_show(struct config_item *item, char *page)
323{
324	return sprintf(page, "%d\n", restore);
325}
326
327static ssize_t config_keys_restore_store(struct config_item *item,
328					  const char *page, size_t count)
329{
330	if (!restore)
331		restore_dm_crypt_keys_to_thread_keyring();
332
333	if (kstrtobool(page, &restore))
334		return -EINVAL;
335
336	return count;
337}
338
339CONFIGFS_ATTR(config_keys_, restore);
340
341static struct configfs_attribute *kdump_config_keys_attrs[] = {
342	&config_keys_attr_restore,
343	NULL,
344};
345
346static const struct config_item_type kdump_config_keys_type = {
347	.ct_attrs = kdump_config_keys_attrs,
348	.ct_owner = THIS_MODULE,
349};
350
351static struct configfs_subsystem config_keys_subsys = {
352	.su_group = {
353		.cg_item = {
354			.ci_namebuf = "crash_dm_crypt_keys",
355			.ci_type = &config_keys_type,
356		},
357	},
358};
359
360static int build_keys_header(void)
361{
362	struct config_item *item = NULL;
363	struct config_key *key;
364	int i, r;
365
366	if (keys_header != NULL)
367		kvfree(keys_header);
368
369	keys_header = kzalloc(get_keys_header_size(key_count), GFP_KERNEL);
370	if (!keys_header)
371		return -ENOMEM;
372
373	keys_header->total_keys = key_count;
374
375	i = 0;
376	list_for_each_entry(item, &config_keys_subsys.su_group.cg_children,
377			    ci_entry) {
378		if (item->ci_type != &config_key_type)
379			continue;
380
381		key = to_config_key(item);
382
383		if (!key->description) {
384			pr_warn("No key description for key %s\n", item->ci_name);
385			return -EINVAL;
386		}
387
388		strscpy(keys_header->keys[i].key_desc, key->description,
389			KEY_DESC_MAX_LEN);
390		r = read_key_from_user_keying(&keys_header->keys[i]);
391		if (r != 0) {
392			kexec_dprintk("Failed to read key %s\n",
393				      keys_header->keys[i].key_desc);
394			return r;
395		}
396		i++;
397		kexec_dprintk("Found key: %s\n", item->ci_name);
398	}
399
400	return 0;
401}
402
403int crash_load_dm_crypt_keys(struct kimage *image)
404{
405	struct kexec_buf kbuf = {
406		.image = image,
407		.buf_min = 0,
408		.buf_max = ULONG_MAX,
409		.top_down = false,
410		.random = true,
411	};
412	int r;
413
414
415	if (key_count <= 0) {
416		kexec_dprintk("No dm-crypt keys\n");
417		return -ENOENT;
418	}
419
420	if (!is_dm_key_reused) {
421		image->dm_crypt_keys_addr = 0;
422		r = build_keys_header();
423		if (r)
424			return r;
425	}
426
427	kbuf.buffer = keys_header;
428	kbuf.bufsz = get_keys_header_size(key_count);
429
430	kbuf.memsz = kbuf.bufsz;
431	kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
432	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
433	r = kexec_add_buffer(&kbuf);
434	if (r) {
435		kvfree((void *)kbuf.buffer);
436		return r;
437	}
438	image->dm_crypt_keys_addr = kbuf.mem;
439	image->dm_crypt_keys_sz = kbuf.bufsz;
440	kexec_dprintk(
441		"Loaded dm crypt keys to kexec_buffer bufsz=0x%lx memsz=0x%lx\n",
442		kbuf.bufsz, kbuf.memsz);
443
444	return r;
445}
446
447static int __init configfs_dmcrypt_keys_init(void)
448{
449	int ret;
450
451	if (is_kdump_kernel()) {
452		config_keys_subsys.su_group.cg_item.ci_type =
453			&kdump_config_keys_type;
454	}
455
456	config_group_init(&config_keys_subsys.su_group);
457	mutex_init(&config_keys_subsys.su_mutex);
458	ret = configfs_register_subsystem(&config_keys_subsys);
459	if (ret) {
460		pr_err("Error %d while registering subsystem %s\n", ret,
461		       config_keys_subsys.su_group.cg_item.ci_namebuf);
462		goto out_unregister;
463	}
464
465	return 0;
466
467out_unregister:
468	configfs_unregister_subsystem(&config_keys_subsys);
469
470	return ret;
471}
472
473module_init(configfs_dmcrypt_keys_init);
~/ Read-only file preview.