Thread (10 messages) 10 messages, 4 authors, 2017-02-06

Re: [PATCH v2 3/3] x86: Make the GDT remapping read-only on 64 bit

From: Thomas Garnier <hidden>
Date: 2017-02-06 22:10:36
Also in: kvm, linux-efi

On Wed, Feb 1, 2017 at 9:14 PM, Andy Lutomirski [off-list ref] wrote:
On Thu, Jan 26, 2017 at 8:59 AM, Thomas Garnier [off-list ref] wrote:
quoted
This patch makes the GDT remapped pages read-only to prevent corruption.
This change is done only on 64 bit.

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 <redacted>
---
Based on next-20170125
---
 arch/x86/include/asm/desc.h      | 46 +++++++++++++++++++++++++++++++++++-----
 arch/x86/include/asm/processor.h |  1 +
 arch/x86/kernel/cpu/common.c     | 28 ++++++++++++++++++------
 arch/x86/kvm/svm.c               |  4 +---
 arch/x86/kvm/vmx.c               | 15 +++++--------
 5 files changed, 70 insertions(+), 24 deletions(-)
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index 4cc176f57b78..ca7b2224fcb4 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -52,6 +52,12 @@ static inline struct desc_struct *get_cpu_direct_gdt(unsigned int cpu)
        return per_cpu(gdt_page, cpu).gdt;
 }

+/* Provide the current original GDT */
+static inline struct desc_struct *get_current_direct_gdt(void)
+{
+       return this_cpu_ptr(&gdt_page)->gdt;
+}
I'm assuming that the reason that this isn't part of patch 2 and used
instead of the version that takes cpu as a parameter is that TLS
doesn't work until the GDT is set up.  If so, perhaps that's worthy of
a comment in patch 2.

But give this_cpu_read(gdt_page.gdt) a try, please.
I tried but I can't get it working properly because the gdt field is
an array, not a pointer. For example with this_cpu_read(gdt_page.gdt),
I get:

./arch/x86/include/asm/desc.h: In function ‘get_current_gdt_rw’:
./include/linux/percpu-defs.h:308:21: error: incompatible types when
assigning to type ‘struct desc_struct[16]’ from type ‘struct
desc_struct *’
  case 1: pscr_ret__ = stem##1(variable); break;   \
                     ^
I tried different variants without success. What do you think?
quoted
+/*
+ * The LTR instruction marks the TSS GDT entry as busy. In 64bit, the GDT is
+ * a read-only remapping. To prevent a page fault, the GDT is switched to the
+ * original writeable version when needed.
+ */
+#ifdef CONFIG_X86_64
+static inline void native_load_tr_desc(void)
+{
+       struct desc_ptr gdt;
+       int cpu = raw_smp_processor_id();
+       bool restore = false;
+       struct desc_struct *fixmap_gdt;
+
+       native_store_gdt(&gdt);
Off the top of my head, this is something like 10 cycles.  IMO that's
fast enough not to worry about the regression this will cause to KVM
exits.  In any event, we'll get that back and *much* more when we do
the optimizations that this series enables.


-- 
Thomas
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help