mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-09 19:16:46 +07:00
69218e4799
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>
148 lines
4.1 KiB
C
148 lines
4.1 KiB
C
/*
|
|
* sleep.c - x86-specific ACPI sleep support.
|
|
*
|
|
* Copyright (C) 2001-2003 Patrick Mochel
|
|
* Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz>
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/cpumask.h>
|
|
#include <asm/segment.h>
|
|
#include <asm/desc.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/realmode.h>
|
|
|
|
#include <linux/ftrace.h>
|
|
#include "../../realmode/rm/wakeup.h"
|
|
#include "sleep.h"
|
|
|
|
unsigned long acpi_realmode_flags;
|
|
|
|
#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
|
|
static char temp_stack[4096];
|
|
#endif
|
|
|
|
/**
|
|
* x86_acpi_enter_sleep_state - enter sleep state
|
|
* @state: Sleep state to enter.
|
|
*
|
|
* Wrapper around acpi_enter_sleep_state() to be called by assmebly.
|
|
*/
|
|
acpi_status asmlinkage __visible x86_acpi_enter_sleep_state(u8 state)
|
|
{
|
|
return acpi_enter_sleep_state(state);
|
|
}
|
|
|
|
/**
|
|
* x86_acpi_suspend_lowlevel - save kernel state
|
|
*
|
|
* Create an identity mapped page table and copy the wakeup routine to
|
|
* low memory.
|
|
*/
|
|
int x86_acpi_suspend_lowlevel(void)
|
|
{
|
|
struct wakeup_header *header =
|
|
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
|
|
|
|
if (header->signature != WAKEUP_HEADER_SIGNATURE) {
|
|
printk(KERN_ERR "wakeup header does not match\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
header->video_mode = saved_video_mode;
|
|
|
|
header->pmode_behavior = 0;
|
|
|
|
#ifndef CONFIG_64BIT
|
|
native_store_gdt((struct desc_ptr *)&header->pmode_gdt);
|
|
|
|
/*
|
|
* We have to check that we can write back the value, and not
|
|
* just read it. At least on 90 nm Pentium M (Family 6, Model
|
|
* 13), reading an invalid MSR is not guaranteed to trap, see
|
|
* Erratum X4 in "Intel Pentium M Processor on 90 nm Process
|
|
* with 2-MB L2 Cache and Intel® Processor A100 and A110 on 90
|
|
* nm process with 512-KB L2 Cache Specification Update".
|
|
*/
|
|
if (!rdmsr_safe(MSR_EFER,
|
|
&header->pmode_efer_low,
|
|
&header->pmode_efer_high) &&
|
|
!wrmsr_safe(MSR_EFER,
|
|
header->pmode_efer_low,
|
|
header->pmode_efer_high))
|
|
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
|
|
#endif /* !CONFIG_64BIT */
|
|
|
|
header->pmode_cr0 = read_cr0();
|
|
if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
|
|
header->pmode_cr4 = __read_cr4();
|
|
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
|
|
}
|
|
if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
|
|
&header->pmode_misc_en_low,
|
|
&header->pmode_misc_en_high) &&
|
|
!wrmsr_safe(MSR_IA32_MISC_ENABLE,
|
|
header->pmode_misc_en_low,
|
|
header->pmode_misc_en_high))
|
|
header->pmode_behavior |=
|
|
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
|
|
header->realmode_flags = acpi_realmode_flags;
|
|
header->real_magic = 0x12345678;
|
|
|
|
#ifndef CONFIG_64BIT
|
|
header->pmode_entry = (u32)&wakeup_pmode_return;
|
|
header->pmode_cr3 = (u32)__pa_symbol(initial_page_table);
|
|
saved_magic = 0x12345678;
|
|
#else /* CONFIG_64BIT */
|
|
#ifdef CONFIG_SMP
|
|
initial_stack = (unsigned long)temp_stack + sizeof(temp_stack);
|
|
early_gdt_descr.address =
|
|
(unsigned long)get_cpu_gdt_rw(smp_processor_id());
|
|
initial_gs = per_cpu_offset(smp_processor_id());
|
|
#endif
|
|
initial_code = (unsigned long)wakeup_long64;
|
|
saved_magic = 0x123456789abcdef0L;
|
|
#endif /* CONFIG_64BIT */
|
|
|
|
/*
|
|
* Pause/unpause graph tracing around do_suspend_lowlevel as it has
|
|
* inconsistent call/return info after it jumps to the wakeup vector.
|
|
*/
|
|
pause_graph_tracing();
|
|
do_suspend_lowlevel();
|
|
unpause_graph_tracing();
|
|
return 0;
|
|
}
|
|
|
|
static int __init acpi_sleep_setup(char *str)
|
|
{
|
|
while ((str != NULL) && (*str != '\0')) {
|
|
if (strncmp(str, "s3_bios", 7) == 0)
|
|
acpi_realmode_flags |= 1;
|
|
if (strncmp(str, "s3_mode", 7) == 0)
|
|
acpi_realmode_flags |= 2;
|
|
if (strncmp(str, "s3_beep", 7) == 0)
|
|
acpi_realmode_flags |= 4;
|
|
#ifdef CONFIG_HIBERNATION
|
|
if (strncmp(str, "s4_nohwsig", 10) == 0)
|
|
acpi_no_s4_hw_signature();
|
|
#endif
|
|
if (strncmp(str, "nonvs", 5) == 0)
|
|
acpi_nvs_nosave();
|
|
if (strncmp(str, "nonvs_s3", 8) == 0)
|
|
acpi_nvs_nosave_s3();
|
|
if (strncmp(str, "old_ordering", 12) == 0)
|
|
acpi_old_suspend_ordering();
|
|
str = strchr(str, ',');
|
|
if (str != NULL)
|
|
str += strspn(str, ", \t");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
__setup("acpi_sleep=", acpi_sleep_setup);
|