a0f7ab8a6a
cherry-pick from upstream 4.14
262 lines
7.9 KiB
Diff
262 lines
7.9 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Mon, 28 Aug 2017 08:47:37 +0200
|
|
Subject: [PATCH] x86/idt: Unify gate_struct handling for 32/64-bit kernels
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
CVE-2017-5754
|
|
|
|
The first 32 bits of gate struct are the same for 32 and 64 bit kernels.
|
|
|
|
The 32-bit version uses desc_struct and no designated data structure,
|
|
so we need different accessors for 32 and 64 bit kernels.
|
|
|
|
Aside of that the macros which are necessary to build the 32-bit
|
|
gate descriptor are horrible to read.
|
|
|
|
Unify the gate structs and switch all code fiddling with it over.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
Cc: Andy Lutomirski <luto@kernel.org>
|
|
Cc: Borislav Petkov <bp@alien8.de>
|
|
Cc: Brian Gerst <brgerst@gmail.com>
|
|
Cc: Denys Vlasenko <dvlasenk@redhat.com>
|
|
Cc: H. Peter Anvin <hpa@zytor.com>
|
|
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
|
|
Cc: Linus Torvalds <torvalds@linux-foundation.org>
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Steven Rostedt <rostedt@goodmis.org>
|
|
Link: http://lkml.kernel.org/r/20170828064957.861974317@linutronix.de
|
|
Signed-off-by: Ingo Molnar <mingo@kernel.org>
|
|
(cherry picked from commit 64b163fab684e3de47aa8db6cc08ae7d2e194373)
|
|
Signed-off-by: Andy Whitcroft <apw@canonical.com>
|
|
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
|
|
(cherry picked from commit 587719b1926757eb7531e0631d63fb93cd60d0d3)
|
|
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
---
|
|
arch/x86/include/asm/desc.h | 45 ++++++++++++++-----------------
|
|
arch/x86/include/asm/desc_defs.h | 57 ++++++++++++++++++++++++++--------------
|
|
arch/x86/kvm/vmx.c | 2 +-
|
|
arch/x86/xen/enlighten_pv.c | 12 ++++-----
|
|
4 files changed, 63 insertions(+), 53 deletions(-)
|
|
|
|
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
|
|
index d0a21b12dd58..57e502a4e92f 100644
|
|
--- a/arch/x86/include/asm/desc.h
|
|
+++ b/arch/x86/include/asm/desc.h
|
|
@@ -83,33 +83,25 @@ static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu)
|
|
return per_cpu_ptr_to_phys(get_cpu_gdt_rw(cpu));
|
|
}
|
|
|
|
-#ifdef CONFIG_X86_64
|
|
-
|
|
static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
|
|
unsigned dpl, unsigned ist, unsigned seg)
|
|
{
|
|
- gate->offset_low = PTR_LOW(func);
|
|
+ gate->offset_low = (u16) func;
|
|
+ gate->bits.p = 1;
|
|
+ gate->bits.dpl = dpl;
|
|
+ gate->bits.zero = 0;
|
|
+ gate->bits.type = type;
|
|
+ gate->offset_middle = (u16) (func >> 16);
|
|
+#ifdef CONFIG_X86_64
|
|
gate->segment = __KERNEL_CS;
|
|
- gate->ist = ist;
|
|
- gate->p = 1;
|
|
- gate->dpl = dpl;
|
|
- gate->zero0 = 0;
|
|
- gate->zero1 = 0;
|
|
- gate->type = type;
|
|
- gate->offset_middle = PTR_MIDDLE(func);
|
|
- gate->offset_high = PTR_HIGH(func);
|
|
-}
|
|
-
|
|
+ gate->bits.ist = ist;
|
|
+ gate->reserved = 0;
|
|
+ gate->offset_high = (u32) (func >> 32);
|
|
#else
|
|
-static inline void pack_gate(gate_desc *gate, unsigned char type,
|
|
- unsigned long base, unsigned dpl, unsigned flags,
|
|
- unsigned short seg)
|
|
-{
|
|
- gate->a = (seg << 16) | (base & 0xffff);
|
|
- gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8);
|
|
-}
|
|
-
|
|
+ gate->segment = seg;
|
|
+ gate->bits.ist = 0;
|
|
#endif
|
|
+}
|
|
|
|
static inline int desc_empty(const void *ptr)
|
|
{
|
|
@@ -185,7 +177,8 @@ static inline void pack_descriptor(struct desc_struct *desc, unsigned long base,
|
|
}
|
|
|
|
|
|
-static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned type, unsigned size)
|
|
+static inline void set_tssldt_descriptor(void *d, unsigned long addr,
|
|
+ unsigned type, unsigned size)
|
|
{
|
|
#ifdef CONFIG_X86_64
|
|
struct ldttss_desc64 *desc = d;
|
|
@@ -193,13 +186,13 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned t
|
|
memset(desc, 0, sizeof(*desc));
|
|
|
|
desc->limit0 = size & 0xFFFF;
|
|
- desc->base0 = PTR_LOW(addr);
|
|
- desc->base1 = PTR_MIDDLE(addr) & 0xFF;
|
|
+ desc->base0 = (u16) addr;
|
|
+ desc->base1 = (addr >> 16) & 0xFF;
|
|
desc->type = type;
|
|
desc->p = 1;
|
|
desc->limit1 = (size >> 16) & 0xF;
|
|
- desc->base2 = (PTR_MIDDLE(addr) >> 8) & 0xFF;
|
|
- desc->base3 = PTR_HIGH(addr);
|
|
+ desc->base2 = (addr >> 24) & 0xFF;
|
|
+ desc->base3 = (u32) (addr >> 32);
|
|
#else
|
|
pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0);
|
|
#endif
|
|
diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h
|
|
index 49265345d4d2..d684bee8a59a 100644
|
|
--- a/arch/x86/include/asm/desc_defs.h
|
|
+++ b/arch/x86/include/asm/desc_defs.h
|
|
@@ -47,20 +47,6 @@ enum {
|
|
GATE_TASK = 0x5,
|
|
};
|
|
|
|
-/* 16byte gate */
|
|
-struct gate_struct64 {
|
|
- u16 offset_low;
|
|
- u16 segment;
|
|
- unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
|
|
- u16 offset_middle;
|
|
- u32 offset_high;
|
|
- u32 zero1;
|
|
-} __attribute__((packed));
|
|
-
|
|
-#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF)
|
|
-#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF)
|
|
-#define PTR_HIGH(x) ((unsigned long long)(x) >> 32)
|
|
-
|
|
enum {
|
|
DESC_TSS = 0x9,
|
|
DESC_LDT = 0x2,
|
|
@@ -77,20 +63,51 @@ struct ldttss_desc64 {
|
|
u32 zero1;
|
|
} __attribute__((packed));
|
|
|
|
+
|
|
#ifdef CONFIG_X86_64
|
|
-typedef struct gate_struct64 gate_desc;
|
|
typedef struct ldttss_desc64 ldt_desc;
|
|
typedef struct ldttss_desc64 tss_desc;
|
|
-#define gate_offset(g) ((g).offset_low | ((unsigned long)(g).offset_middle << 16) | ((unsigned long)(g).offset_high << 32))
|
|
-#define gate_segment(g) ((g).segment)
|
|
#else
|
|
-typedef struct desc_struct gate_desc;
|
|
typedef struct desc_struct ldt_desc;
|
|
typedef struct desc_struct tss_desc;
|
|
-#define gate_offset(g) (((g).b & 0xffff0000) | ((g).a & 0x0000ffff))
|
|
-#define gate_segment(g) ((g).a >> 16)
|
|
#endif
|
|
|
|
+struct idt_bits {
|
|
+ u16 ist : 3,
|
|
+ zero : 5,
|
|
+ type : 5,
|
|
+ dpl : 2,
|
|
+ p : 1;
|
|
+} __attribute__((packed));
|
|
+
|
|
+struct gate_struct {
|
|
+ u16 offset_low;
|
|
+ u16 segment;
|
|
+ struct idt_bits bits;
|
|
+ u16 offset_middle;
|
|
+#ifdef CONFIG_X86_64
|
|
+ u32 offset_high;
|
|
+ u32 reserved;
|
|
+#endif
|
|
+} __attribute__((packed));
|
|
+
|
|
+typedef struct gate_struct gate_desc;
|
|
+
|
|
+static inline unsigned long gate_offset(const gate_desc *g)
|
|
+{
|
|
+#ifdef CONFIG_X86_64
|
|
+ return g->offset_low | ((unsigned long)g->offset_middle << 16) |
|
|
+ ((unsigned long) g->offset_high << 32);
|
|
+#else
|
|
+ return g->offset_low | ((unsigned long)g->offset_middle << 16);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static inline unsigned long gate_segment(const gate_desc *g)
|
|
+{
|
|
+ return g->segment;
|
|
+}
|
|
+
|
|
struct desc_ptr {
|
|
unsigned short size;
|
|
unsigned long address;
|
|
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
|
index a2c95522ac99..7b447d126d17 100644
|
|
--- a/arch/x86/kvm/vmx.c
|
|
+++ b/arch/x86/kvm/vmx.c
|
|
@@ -8838,7 +8838,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
|
|
|
|
vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
|
|
desc = (gate_desc *)vmx->host_idt_base + vector;
|
|
- entry = gate_offset(*desc);
|
|
+ entry = gate_offset(desc);
|
|
asm volatile(
|
|
#ifdef CONFIG_X86_64
|
|
"mov %%" _ASM_SP ", %[sp]\n\t"
|
|
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
|
|
index 6c279c8f0a0e..49ee3315b9f7 100644
|
|
--- a/arch/x86/xen/enlighten_pv.c
|
|
+++ b/arch/x86/xen/enlighten_pv.c
|
|
@@ -591,12 +591,12 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
|
{
|
|
unsigned long addr;
|
|
|
|
- if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT)
|
|
+ if (val->bits.type != GATE_TRAP && val->bits.type != GATE_INTERRUPT)
|
|
return 0;
|
|
|
|
info->vector = vector;
|
|
|
|
- addr = gate_offset(*val);
|
|
+ addr = gate_offset(val);
|
|
#ifdef CONFIG_X86_64
|
|
/*
|
|
* Look for known traps using IST, and substitute them
|
|
@@ -629,16 +629,16 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
|
;
|
|
else {
|
|
/* Some other trap using IST? */
|
|
- if (WARN_ON(val->ist != 0))
|
|
+ if (WARN_ON(val->bits.ist != 0))
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_X86_64 */
|
|
info->address = addr;
|
|
|
|
- info->cs = gate_segment(*val);
|
|
- info->flags = val->dpl;
|
|
+ info->cs = gate_segment(val);
|
|
+ info->flags = val->bits.dpl;
|
|
/* interrupt gates clear IF */
|
|
- if (val->type == GATE_INTERRUPT)
|
|
+ if (val->bits.type == GATE_INTERRUPT)
|
|
info->flags |= 1 << 2;
|
|
|
|
return 1;
|
|
--
|
|
2.14.2
|
|
|