aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKairui Song <kasong@redhat.com>2019-03-07 22:05:08 -0500
committerThomas Gleixner <tglx@linutronix.de>2019-03-23 07:11:49 -0400
commitffc8599aa9763f39f6736a79da4d1575e7006f9a (patch)
tree564374b91fdfced43fbcbf2310cb05e3ca9759a4
parentf7798711adeebde3c59ddd797a3f2da36c1005be (diff)
x86/gart: Exclude GART aperture from kcore
On machines where the GART aperture is mapped over physical RAM, /proc/kcore contains the GART aperture range. Accessing the GART range via /proc/kcore results in a kernel crash. vmcore used to have the same issue, until it was fixed with commit 2a3e83c6f96c ("x86/gart: Exclude GART aperture from vmcore")', leveraging existing hook infrastructure in vmcore to let /proc/vmcore return zeroes when attempting to read the aperture region, and so it won't read from the actual memory. Apply the same workaround for kcore. First implement the same hook infrastructure for kcore, then reuse the hook functions introduced in the previous vmcore fix. Just with some minor adjustment, rename some functions for more general usage, and simplify the hook infrastructure a bit as there is no module usage yet. Suggested-by: Baoquan He <bhe@redhat.com> Signed-off-by: Kairui Song <kasong@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Jiri Bohac <jbohac@suse.cz> Acked-by: Baoquan He <bhe@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Omar Sandoval <osandov@fb.com> Cc: Dave Young <dyoung@redhat.com> Link: https://lkml.kernel.org/r/20190308030508.13548-1-kasong@redhat.com
-rw-r--r--arch/x86/kernel/aperture_64.c20
-rw-r--r--fs/proc/kcore.c27
-rw-r--r--include/linux/kcore.h2
3 files changed, 42 insertions, 7 deletions
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 58176b56354e..294ed4392a0e 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -14,6 +14,7 @@
14#define pr_fmt(fmt) "AGP: " fmt 14#define pr_fmt(fmt) "AGP: " fmt
15 15
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/kcore.h>
17#include <linux/types.h> 18#include <linux/types.h>
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/memblock.h> 20#include <linux/memblock.h>
@@ -57,7 +58,7 @@ int fallback_aper_force __initdata;
57 58
58int fix_aperture __initdata = 1; 59int fix_aperture __initdata = 1;
59 60
60#ifdef CONFIG_PROC_VMCORE 61#if defined(CONFIG_PROC_VMCORE) || defined(CONFIG_PROC_KCORE)
61/* 62/*
62 * If the first kernel maps the aperture over e820 RAM, the kdump kernel will 63 * If the first kernel maps the aperture over e820 RAM, the kdump kernel will
63 * use the same range because it will remain configured in the northbridge. 64 * use the same range because it will remain configured in the northbridge.
@@ -66,20 +67,25 @@ int fix_aperture __initdata = 1;
66 */ 67 */
67static unsigned long aperture_pfn_start, aperture_page_count; 68static unsigned long aperture_pfn_start, aperture_page_count;
68 69
69static int gart_oldmem_pfn_is_ram(unsigned long pfn) 70static int gart_mem_pfn_is_ram(unsigned long pfn)
70{ 71{
71 return likely((pfn < aperture_pfn_start) || 72 return likely((pfn < aperture_pfn_start) ||
72 (pfn >= aperture_pfn_start + aperture_page_count)); 73 (pfn >= aperture_pfn_start + aperture_page_count));
73} 74}
74 75
75static void exclude_from_vmcore(u64 aper_base, u32 aper_order) 76static void __init exclude_from_core(u64 aper_base, u32 aper_order)
76{ 77{
77 aperture_pfn_start = aper_base >> PAGE_SHIFT; 78 aperture_pfn_start = aper_base >> PAGE_SHIFT;
78 aperture_page_count = (32 * 1024 * 1024) << aper_order >> PAGE_SHIFT; 79 aperture_page_count = (32 * 1024 * 1024) << aper_order >> PAGE_SHIFT;
79 WARN_ON(register_oldmem_pfn_is_ram(&gart_oldmem_pfn_is_ram)); 80#ifdef CONFIG_PROC_VMCORE
81 WARN_ON(register_oldmem_pfn_is_ram(&gart_mem_pfn_is_ram));
82#endif
83#ifdef CONFIG_PROC_KCORE
84 WARN_ON(register_mem_pfn_is_ram(&gart_mem_pfn_is_ram));
85#endif
80} 86}
81#else 87#else
82static void exclude_from_vmcore(u64 aper_base, u32 aper_order) 88static void exclude_from_core(u64 aper_base, u32 aper_order)
83{ 89{
84} 90}
85#endif 91#endif
@@ -474,7 +480,7 @@ out:
474 * may have allocated the range over its e820 RAM 480 * may have allocated the range over its e820 RAM
475 * and fixed up the northbridge 481 * and fixed up the northbridge
476 */ 482 */
477 exclude_from_vmcore(last_aper_base, last_aper_order); 483 exclude_from_core(last_aper_base, last_aper_order);
478 484
479 return 1; 485 return 1;
480 } 486 }
@@ -520,7 +526,7 @@ out:
520 * overlap with the first kernel's memory. We can't access the 526 * overlap with the first kernel's memory. We can't access the
521 * range through vmcore even though it should be part of the dump. 527 * range through vmcore even though it should be part of the dump.
522 */ 528 */
523 exclude_from_vmcore(aper_alloc, aper_order); 529 exclude_from_core(aper_alloc, aper_order);
524 530
525 /* Fix up the north bridges */ 531 /* Fix up the north bridges */
526 for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 532 for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) {
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index bbcc185062bb..d29d869abec1 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -54,6 +54,28 @@ static LIST_HEAD(kclist_head);
54static DECLARE_RWSEM(kclist_lock); 54static DECLARE_RWSEM(kclist_lock);
55static int kcore_need_update = 1; 55static int kcore_need_update = 1;
56 56
57/*
58 * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
59 * Same as oldmem_pfn_is_ram in vmcore
60 */
61static int (*mem_pfn_is_ram)(unsigned long pfn);
62
63int __init register_mem_pfn_is_ram(int (*fn)(unsigned long pfn))
64{
65 if (mem_pfn_is_ram)
66 return -EBUSY;
67 mem_pfn_is_ram = fn;
68 return 0;
69}
70
71static int pfn_is_ram(unsigned long pfn)
72{
73 if (mem_pfn_is_ram)
74 return mem_pfn_is_ram(pfn);
75 else
76 return 1;
77}
78
57/* This doesn't grab kclist_lock, so it should only be used at init time. */ 79/* This doesn't grab kclist_lock, so it should only be used at init time. */
58void __init kclist_add(struct kcore_list *new, void *addr, size_t size, 80void __init kclist_add(struct kcore_list *new, void *addr, size_t size,
59 int type) 81 int type)
@@ -465,6 +487,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
465 goto out; 487 goto out;
466 } 488 }
467 m = NULL; /* skip the list anchor */ 489 m = NULL; /* skip the list anchor */
490 } else if (!pfn_is_ram(__pa(start) >> PAGE_SHIFT)) {
491 if (clear_user(buffer, tsz)) {
492 ret = -EFAULT;
493 goto out;
494 }
468 } else if (m->type == KCORE_VMALLOC) { 495 } else if (m->type == KCORE_VMALLOC) {
469 vread(buf, (char *)start, tsz); 496 vread(buf, (char *)start, tsz);
470 /* we have to zero-fill user buffer even if no read */ 497 /* we have to zero-fill user buffer even if no read */
diff --git a/include/linux/kcore.h b/include/linux/kcore.h
index 8c3f8c14eeaa..c843f4a9c512 100644
--- a/include/linux/kcore.h
+++ b/include/linux/kcore.h
@@ -44,6 +44,8 @@ void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
44 m->vaddr = (unsigned long)vaddr; 44 m->vaddr = (unsigned long)vaddr;
45 kclist_add(m, addr, sz, KCORE_REMAP); 45 kclist_add(m, addr, sz, KCORE_REMAP);
46} 46}
47
48extern int __init register_mem_pfn_is_ram(int (*fn)(unsigned long pfn));
47#else 49#else
48static inline 50static inline
49void kclist_add(struct kcore_list *new, void *addr, size_t size, int type) 51void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)