kexec: introduce a protection mechanism for the crashkernel reserved memory
authorXunlei Pang <xlpang@redhat.com>
Mon, 23 May 2016 23:24:10 +0000 (16:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 24 May 2016 00:04:14 +0000 (17:04 -0700)
For the cases that some kernel (module) path stamps the crash reserved
memory(already mapped by the kernel) where has been loaded the second
kernel data, the kdump kernel will probably fail to boot when panic
happens (or even not happens) leaving the culprit at large, this is
unacceptable.

The patch introduces a mechanism for detecting such cases:

1) After each crash kexec loading, it simply marks the reserved memory
   regions readonly since we no longer access it after that.  When someone
   stamps the region, the first kernel will panic and trigger the kdump.
   The weak arch_kexec_protect_crashkres() is introduced to do the actual
   protection.

2) To allow multiple loading, once 1) was done we also need to remark
   the reserved memory to readwrite each time a system call related to
   kdump is made.  The weak arch_kexec_unprotect_crashkres() is introduced
   to do the actual protection.

The architecture can make its specific implementation by overriding
arch_kexec_protect_crashkres() and arch_kexec_unprotect_crashkres().

Signed-off-by: Xunlei Pang <xlpang@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Minfei Huang <mhuang@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/kexec.h
kernel/kexec.c
kernel/kexec_core.c
kernel/kexec_file.c

index 2cc643c6e8708207aea022d0e1f790f805364be2..643ff4a3fbf6b3535d20bd86b43850fefa091e02 100644 (file)
@@ -317,6 +317,8 @@ int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr,
                                        Elf_Shdr *sechdrs, unsigned int relsec);
 int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
                                        unsigned int relsec);
+void arch_kexec_protect_crashkres(void);
+void arch_kexec_unprotect_crashkres(void);
 
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
index ee70aef5cd81dfb7ee5c4397b91810b0109a58b8..b44cb3f5a15ce0faef496b948d039bdf73b21f74 100644 (file)
@@ -167,8 +167,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
                return -EBUSY;
 
        dest_image = &kexec_image;
-       if (flags & KEXEC_ON_CRASH)
+       if (flags & KEXEC_ON_CRASH) {
                dest_image = &kexec_crash_image;
+               if (kexec_crash_image)
+                       arch_kexec_unprotect_crashkres();
+       }
+
        if (nr_segments > 0) {
                unsigned long i;
 
@@ -211,6 +215,9 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
        image = xchg(dest_image, image);
 
 out:
+       if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
+               arch_kexec_protect_crashkres();
+
        mutex_unlock(&kexec_mutex);
        kimage_free(image);
 
index d5d40825299227d17ddfaf94fd36ecada8c69349..48b73cc8e42508933dc4cb813c3eb77f87098a8f 100644 (file)
@@ -1563,3 +1563,9 @@ void __weak crash_map_reserved_pages(void)
 
 void __weak crash_unmap_reserved_pages(void)
 {}
+
+void __weak arch_kexec_protect_crashkres(void)
+{}
+
+void __weak arch_kexec_unprotect_crashkres(void)
+{}
index c72d2ff5896e9f37e21c789d45d7b2cc058be9f0..503bc2d348e59aa2f866a4ad5b79d913419e862b 100644 (file)
@@ -274,8 +274,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
                return -EBUSY;
 
        dest_image = &kexec_image;
-       if (flags & KEXEC_FILE_ON_CRASH)
+       if (flags & KEXEC_FILE_ON_CRASH) {
                dest_image = &kexec_crash_image;
+               if (kexec_crash_image)
+                       arch_kexec_unprotect_crashkres();
+       }
 
        if (flags & KEXEC_FILE_UNLOAD)
                goto exchange;
@@ -324,6 +327,9 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
 exchange:
        image = xchg(dest_image, image);
 out:
+       if ((flags & KEXEC_FILE_ON_CRASH) && kexec_crash_image)
+               arch_kexec_protect_crashkres();
+
        mutex_unlock(&kexec_mutex);
        kimage_free(image);
        return ret;