aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorXunlei Pang <xlpang@redhat.com>2017-07-12 17:33:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-12 19:26:00 -0400
commit1229384f5b856d83698c38f9dedfd836e26711cb (patch)
treefb797eeab18938f30aa26aab8fd5c270cf0719e7 /kernel
parent5203f4995d9a87952a83c2ce7866adbbe8f97bb5 (diff)
kdump: protect vmcoreinfo data under the crash memory
Currently vmcoreinfo data is updated at boot time subsys_initcall(), it has the risk of being modified by some wrong code during system is running. As a result, vmcore dumped may contain the wrong vmcoreinfo. Later on, when using "crash", "makedumpfile", etc utility to parse this vmcore, we probably will get "Segmentation fault" or other unexpected errors. E.g. 1) wrong code overwrites vmcoreinfo_data; 2) further crashes the system; 3) trigger kdump, then we obviously will fail to recognize the crash context correctly due to the corrupted vmcoreinfo. Now except for vmcoreinfo, all the crash data is well protected(including the cpu note which is fully updated in the crash path, thus its correctness is guaranteed). Given that vmcoreinfo data is a large chunk prepared for kdump, we better protect it as well. To solve this, we relocate and copy vmcoreinfo_data to the crash memory when kdump is loading via kexec syscalls. Because the whole crash memory will be protected by existing arch_kexec_protect_crashkres() mechanism, we naturally protect vmcoreinfo_data from write(even read) access under kernel direct mapping after kdump is loaded. Since kdump is usually loaded at the very early stage after boot, we can trust the correctness of the vmcoreinfo data copied. On the other hand, we still need to operate the vmcoreinfo safe copy when crash happens to generate vmcoreinfo_note again, we rely on vmap() to map out a new kernel virtual address and update to use this new one instead in the following crash_save_vmcoreinfo(). BTW, we do not touch vmcoreinfo_note, because it will be fully updated using the protected vmcoreinfo_data after crash which is surely correct just like the cpu crash note. Link: http://lkml.kernel.org/r/1493281021-20737-3-git-send-email-xlpang@redhat.com Signed-off-by: Xunlei Pang <xlpang@redhat.com> Tested-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Dave Young <dyoung@redhat.com> Cc: Eric Biederman <ebiederm@xmission.com> Cc: Hari Bathini <hbathini@linux.vnet.ibm.com> Cc: Juergen Gross <jgross@suse.com> Cc: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/crash_core.c17
-rw-r--r--kernel/kexec.c8
-rw-r--r--kernel/kexec_core.c39
-rw-r--r--kernel/kexec_file.c8
4 files changed, 71 insertions, 1 deletions
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 315adbf9cb68..6db80fc0810b 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -15,9 +15,12 @@
15 15
16/* vmcoreinfo stuff */ 16/* vmcoreinfo stuff */
17static unsigned char *vmcoreinfo_data; 17static unsigned char *vmcoreinfo_data;
18size_t vmcoreinfo_size; 18static size_t vmcoreinfo_size;
19u32 *vmcoreinfo_note; 19u32 *vmcoreinfo_note;
20 20
21/* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
22static unsigned char *vmcoreinfo_data_safecopy;
23
21/* 24/*
22 * parsing the "crashkernel" commandline 25 * parsing the "crashkernel" commandline
23 * 26 *
@@ -323,11 +326,23 @@ static void update_vmcoreinfo_note(void)
323 final_note(buf); 326 final_note(buf);
324} 327}
325 328
329void crash_update_vmcoreinfo_safecopy(void *ptr)
330{
331 if (ptr)
332 memcpy(ptr, vmcoreinfo_data, vmcoreinfo_size);
333
334 vmcoreinfo_data_safecopy = ptr;
335}
336
326void crash_save_vmcoreinfo(void) 337void crash_save_vmcoreinfo(void)
327{ 338{
328 if (!vmcoreinfo_note) 339 if (!vmcoreinfo_note)
329 return; 340 return;
330 341
342 /* Use the safe copy to generate vmcoreinfo note if have */
343 if (vmcoreinfo_data_safecopy)
344 vmcoreinfo_data = vmcoreinfo_data_safecopy;
345
331 vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds()); 346 vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds());
332 update_vmcoreinfo_note(); 347 update_vmcoreinfo_note();
333} 348}
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 980936a90ee6..e62ec4dc6620 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -144,6 +144,14 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
144 if (ret) 144 if (ret)
145 goto out; 145 goto out;
146 146
147 /*
148 * Some architecture(like S390) may touch the crash memory before
149 * machine_kexec_prepare(), we must copy vmcoreinfo data after it.
150 */
151 ret = kimage_crash_copy_vmcoreinfo(image);
152 if (ret)
153 goto out;
154
147 for (i = 0; i < nr_segments; i++) { 155 for (i = 0; i < nr_segments; i++) {
148 ret = kimage_load_segment(image, &image->segment[i]); 156 ret = kimage_load_segment(image, &image->segment[i]);
149 if (ret) 157 if (ret)
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 154ffb489b93..1ae7c41c33c1 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -482,6 +482,40 @@ struct page *kimage_alloc_control_pages(struct kimage *image,
482 return pages; 482 return pages;
483} 483}
484 484
485int kimage_crash_copy_vmcoreinfo(struct kimage *image)
486{
487 struct page *vmcoreinfo_page;
488 void *safecopy;
489
490 if (image->type != KEXEC_TYPE_CRASH)
491 return 0;
492
493 /*
494 * For kdump, allocate one vmcoreinfo safe copy from the
495 * crash memory. as we have arch_kexec_protect_crashkres()
496 * after kexec syscall, we naturally protect it from write
497 * (even read) access under kernel direct mapping. But on
498 * the other hand, we still need to operate it when crash
499 * happens to generate vmcoreinfo note, hereby we rely on
500 * vmap for this purpose.
501 */
502 vmcoreinfo_page = kimage_alloc_control_pages(image, 0);
503 if (!vmcoreinfo_page) {
504 pr_warn("Could not allocate vmcoreinfo buffer\n");
505 return -ENOMEM;
506 }
507 safecopy = vmap(&vmcoreinfo_page, 1, VM_MAP, PAGE_KERNEL);
508 if (!safecopy) {
509 pr_warn("Could not vmap vmcoreinfo buffer\n");
510 return -ENOMEM;
511 }
512
513 image->vmcoreinfo_data_copy = safecopy;
514 crash_update_vmcoreinfo_safecopy(safecopy);
515
516 return 0;
517}
518
485static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) 519static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
486{ 520{
487 if (*image->entry != 0) 521 if (*image->entry != 0)
@@ -569,6 +603,11 @@ void kimage_free(struct kimage *image)
569 if (!image) 603 if (!image)
570 return; 604 return;
571 605
606 if (image->vmcoreinfo_data_copy) {
607 crash_update_vmcoreinfo_safecopy(NULL);
608 vunmap(image->vmcoreinfo_data_copy);
609 }
610
572 kimage_free_extra_pages(image); 611 kimage_free_extra_pages(image);
573 for_each_kimage_entry(image, ptr, entry) { 612 for_each_kimage_entry(image, ptr, entry) {
574 if (entry & IND_INDIRECTION) { 613 if (entry & IND_INDIRECTION) {
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 766e7e4d3ad9..c8f7f77e9fa9 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -298,6 +298,14 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
298 if (ret) 298 if (ret)
299 goto out; 299 goto out;
300 300
301 /*
302 * Some architecture(like S390) may touch the crash memory before
303 * machine_kexec_prepare(), we must copy vmcoreinfo data after it.
304 */
305 ret = kimage_crash_copy_vmcoreinfo(image);
306 if (ret)
307 goto out;
308
301 ret = kexec_calculate_store_digests(image); 309 ret = kexec_calculate_store_digests(image);
302 if (ret) 310 if (ret)
303 goto out; 311 goto out;