projects/linux·blob master · refs

482 lines · 10.8 KiB

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