Skip to content

Commit ffc8599

Browse files
ryncsnKAGA-KOKO
authored andcommitted
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 2a3e83c ("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
1 parent f779871 commit ffc8599

File tree

3 files changed

+42
-7
lines changed

3 files changed

+42
-7
lines changed

arch/x86/kernel/aperture_64.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define pr_fmt(fmt) "AGP: " fmt
1515

1616
#include <linux/kernel.h>
17+
#include <linux/kcore.h>
1718
#include <linux/types.h>
1819
#include <linux/init.h>
1920
#include <linux/memblock.h>
@@ -57,7 +58,7 @@ int fallback_aper_force __initdata;
5758

5859
int fix_aperture __initdata = 1;
5960

60-
#ifdef CONFIG_PROC_VMCORE
61+
#if defined(CONFIG_PROC_VMCORE) || defined(CONFIG_PROC_KCORE)
6162
/*
6263
* If the first kernel maps the aperture over e820 RAM, the kdump kernel will
6364
* use the same range because it will remain configured in the northbridge.
@@ -66,20 +67,25 @@ int fix_aperture __initdata = 1;
6667
*/
6768
static unsigned long aperture_pfn_start, aperture_page_count;
6869

69-
static int gart_oldmem_pfn_is_ram(unsigned long pfn)
70+
static int gart_mem_pfn_is_ram(unsigned long pfn)
7071
{
7172
return likely((pfn < aperture_pfn_start) ||
7273
(pfn >= aperture_pfn_start + aperture_page_count));
7374
}
7475

75-
static void exclude_from_vmcore(u64 aper_base, u32 aper_order)
76+
static void __init exclude_from_core(u64 aper_base, u32 aper_order)
7677
{
7778
aperture_pfn_start = aper_base >> PAGE_SHIFT;
7879
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
8086
}
8187
#else
82-
static void exclude_from_vmcore(u64 aper_base, u32 aper_order)
88+
static void exclude_from_core(u64 aper_base, u32 aper_order)
8389
{
8490
}
8591
#endif
@@ -474,7 +480,7 @@ int __init gart_iommu_hole_init(void)
474480
* may have allocated the range over its e820 RAM
475481
* and fixed up the northbridge
476482
*/
477-
exclude_from_vmcore(last_aper_base, last_aper_order);
483+
exclude_from_core(last_aper_base, last_aper_order);
478484

479485
return 1;
480486
}
@@ -520,7 +526,7 @@ int __init gart_iommu_hole_init(void)
520526
* overlap with the first kernel's memory. We can't access the
521527
* range through vmcore even though it should be part of the dump.
522528
*/
523-
exclude_from_vmcore(aper_alloc, aper_order);
529+
exclude_from_core(aper_alloc, aper_order);
524530

525531
/* Fix up the north bridges */
526532
for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) {

fs/proc/kcore.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,28 @@ static LIST_HEAD(kclist_head);
5454
static DECLARE_RWSEM(kclist_lock);
5555
static int kcore_need_update = 1;
5656

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+
*/
61+
static int (*mem_pfn_is_ram)(unsigned long pfn);
62+
63+
int __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+
71+
static 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+
5779
/* This doesn't grab kclist_lock, so it should only be used at init time. */
5880
void __init kclist_add(struct kcore_list *new, void *addr, size_t size,
5981
int type)
@@ -465,6 +487,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
465487
goto out;
466488
}
467489
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+
}
468495
} else if (m->type == KCORE_VMALLOC) {
469496
vread(buf, (char *)start, tsz);
470497
/* we have to zero-fill user buffer even if no read */

include/linux/kcore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
4444
m->vaddr = (unsigned long)vaddr;
4545
kclist_add(m, addr, sz, KCORE_REMAP);
4646
}
47+
48+
extern int __init register_mem_pfn_is_ram(int (*fn)(unsigned long pfn));
4749
#else
4850
static inline
4951
void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)

0 commit comments

Comments
 (0)