x86: Make the GDT remapping read-only on 64-bit
This patch makes the GDT remapped pages read-only, to prevent accidental (or intentional) corruption of this key data structure. This change is done only on 64-bit, because 32-bit needs it to be writable for TSS switches. The native_load_tr_desc function was adapted to correctly handle a read-only GDT. The LTR instruction always writes to the GDT TSS entry. This generates a page fault if the GDT is read-only. This change checks if the current GDT is a remap and swap GDTs as needed. This function was tested by booting multiple machines and checking hibernation works properly. KVM SVM and VMX were adapted to use the writeable GDT. On VMX, the per-cpu variable was removed for functions to fetch the original GDT. Instead of reloading the previous GDT, VMX will reload the fixmap GDT as expected. For testing, VMs were started and restored on multiple configurations. 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-3-thgarnie@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:

committed by
Ingo Molnar

parent
69218e4799
commit
45fc8757d1
@@ -935,7 +935,6 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
|
||||
* when a CPU is brought down, and we need to VMCLEAR all VMCSs loaded on it.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct list_head, loaded_vmcss_on_cpu);
|
||||
static DEFINE_PER_CPU(struct desc_ptr, host_gdt);
|
||||
|
||||
/*
|
||||
* We maintian a per-CPU linked-list of vCPU, so in wakeup_handler() we
|
||||
@@ -2052,14 +2051,13 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
|
||||
*/
|
||||
static unsigned long segment_base(u16 selector)
|
||||
{
|
||||
struct desc_ptr *gdt = this_cpu_ptr(&host_gdt);
|
||||
struct desc_struct *table;
|
||||
unsigned long v;
|
||||
|
||||
if (!(selector & ~SEGMENT_RPL_MASK))
|
||||
return 0;
|
||||
|
||||
table = (struct desc_struct *)gdt->address;
|
||||
table = get_current_gdt_ro();
|
||||
|
||||
if ((selector & SEGMENT_TI_MASK) == SEGMENT_LDT) {
|
||||
u16 ldt_selector = kvm_read_ldt();
|
||||
@@ -2164,7 +2162,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||
#endif
|
||||
if (vmx->host_state.msr_host_bndcfgs)
|
||||
wrmsrl(MSR_IA32_BNDCFGS, vmx->host_state.msr_host_bndcfgs);
|
||||
load_gdt(this_cpu_ptr(&host_gdt));
|
||||
load_fixmap_gdt(raw_smp_processor_id());
|
||||
}
|
||||
|
||||
static void vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||
@@ -2266,7 +2264,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
}
|
||||
|
||||
if (!already_loaded) {
|
||||
struct desc_ptr *gdt = this_cpu_ptr(&host_gdt);
|
||||
unsigned long gdt = get_current_gdt_ro_vaddr();
|
||||
unsigned long sysenter_esp;
|
||||
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
|
||||
@@ -2277,7 +2275,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
*/
|
||||
vmcs_writel(HOST_TR_BASE,
|
||||
(unsigned long)this_cpu_ptr(&cpu_tss));
|
||||
vmcs_writel(HOST_GDTR_BASE, gdt->address);
|
||||
vmcs_writel(HOST_GDTR_BASE, gdt); /* 22.2.4 */
|
||||
|
||||
/*
|
||||
* VM exits change the host TR limit to 0x67 after a VM
|
||||
@@ -3465,8 +3463,6 @@ static int hardware_enable(void)
|
||||
ept_sync_global();
|
||||
}
|
||||
|
||||
native_store_gdt(this_cpu_ptr(&host_gdt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user