Each processor holds a GDT in its per-cpu structure. The sgdt instruction gives the base address of the current GDT. This address can be used to bypass KASLR memory randomization. With another bug, an attacker could target other per-cpu structures or deduce the base of the main memory section (PAGE_OFFSET). This patch relocates the GDT table for each processor inside the fixmap section. The space is reserved based on number of supported processors. For consistency, the remapping is done by default on 32 and 64-bit. Each processor switches to its remapped GDT at the end of initialization. For hibernation, the main processor returns with the original GDT and switches back to the remapping at completion. This patch was tested on both architectures. Hibernation and KVM were both tested specially for their usage of the GDT. Thanks to Boris Ostrovsky <boris.ostrovsky@oracle.com> for testing and recommending changes for Xen support. Signed-off-by: Thomas Garnier <thgarnie@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Borislav Petkov <bp@suse.de> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Kosina <jikos@kernel.org> Cc: Joerg Roedel <joro@8bytes.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Kees Cook <keescook@chromium.org> Cc: Len Brown <len.brown@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Lorenzo Stoakes <lstoakes@gmail.com> Cc: Luis R . Rodriguez <mcgrof@kernel.org> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Michal Hocko <mhocko@suse.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Rafael J . Wysocki <rjw@rjwysocki.net> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: kasan-dev@googlegroups.com Cc: kernel-hardening@lists.openwall.com Cc: kvm@vger.kernel.org Cc: lguest@lists.ozlabs.org Cc: linux-doc@vger.kernel.org Cc: linux-efi@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pm@vger.kernel.org Cc: xen-devel@lists.xenproject.org Cc: zijun_hu <zijun_hu@htc.com> Link: http://lkml.kernel.org/r/20170314170508.100882-2-thgarnie@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
95 lines
2.3 KiB
C
95 lines
2.3 KiB
C
/*
|
|
* Extensible Firmware Interface
|
|
*
|
|
* Based on Extensible Firmware Interface Specification version 1.0
|
|
*
|
|
* Copyright (C) 1999 VA Linux Systems
|
|
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
|
|
* Copyright (C) 1999-2002 Hewlett-Packard Co.
|
|
* David Mosberger-Tang <davidm@hpl.hp.com>
|
|
* Stephane Eranian <eranian@hpl.hp.com>
|
|
*
|
|
* All EFI Runtime Services are not implemented yet as EFI only
|
|
* supports physical mode addressing on SoftSDV. This is to be fixed
|
|
* in a future version. --drummond 1999-07-20
|
|
*
|
|
* Implemented EFI runtime services and virtual mode calls. --davidm
|
|
*
|
|
* Goutham Rao: <goutham.rao@intel.com>
|
|
* Skip non-WB memory and ignore empty memory ranges.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/efi.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/desc.h>
|
|
#include <asm/page.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/efi.h>
|
|
|
|
/*
|
|
* To make EFI call EFI runtime service in physical addressing mode we need
|
|
* prolog/epilog before/after the invocation to claim the EFI runtime service
|
|
* handler exclusively and to duplicate a memory mapping in low memory space,
|
|
* say 0 - 3G.
|
|
*/
|
|
|
|
int __init efi_alloc_page_tables(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void efi_sync_low_kernel_mappings(void) {}
|
|
void __init efi_dump_pagetable(void) {}
|
|
int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void __init efi_map_region(efi_memory_desc_t *md)
|
|
{
|
|
old_map_region(md);
|
|
}
|
|
|
|
void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
|
|
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
|
|
|
|
pgd_t * __init efi_call_phys_prolog(void)
|
|
{
|
|
struct desc_ptr gdt_descr;
|
|
pgd_t *save_pgd;
|
|
|
|
/* Current pgd is swapper_pg_dir, we'll restore it later: */
|
|
save_pgd = swapper_pg_dir;
|
|
load_cr3(initial_page_table);
|
|
__flush_tlb_all();
|
|
|
|
gdt_descr.address = __pa(get_cpu_gdt_rw(0));
|
|
gdt_descr.size = GDT_SIZE - 1;
|
|
load_gdt(&gdt_descr);
|
|
|
|
return save_pgd;
|
|
}
|
|
|
|
void __init efi_call_phys_epilog(pgd_t *save_pgd)
|
|
{
|
|
struct desc_ptr gdt_descr;
|
|
|
|
gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0);
|
|
gdt_descr.size = GDT_SIZE - 1;
|
|
load_gdt(&gdt_descr);
|
|
|
|
load_cr3(save_pgd);
|
|
__flush_tlb_all();
|
|
}
|
|
|
|
void __init efi_runtime_update_mappings(void)
|
|
{
|
|
if (__supported_pte_mask & _PAGE_NX)
|
|
runtime_code_page_mkexec();
|
|
}
|