]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From 12f71c3ef98c53a158abec93ef40cd15c9120284 Mon Sep 17 00:00:00 2001 |
2 | From: Thomas Gleixner <tglx@linutronix.de> | |
3 | Date: Mon, 28 Aug 2017 08:47:37 +0200 | |
b378f209 | 4 | Subject: [PATCH 027/233] x86/idt: Unify gate_struct handling for 32/64-bit |
321d628a FG |
5 | kernels |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5754 | |
11 | ||
12 | The first 32 bits of gate struct are the same for 32 and 64 bit kernels. | |
13 | ||
14 | The 32-bit version uses desc_struct and no designated data structure, | |
15 | so we need different accessors for 32 and 64 bit kernels. | |
16 | ||
17 | Aside of that the macros which are necessary to build the 32-bit | |
18 | gate descriptor are horrible to read. | |
19 | ||
20 | Unify the gate structs and switch all code fiddling with it over. | |
21 | ||
22 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
23 | Cc: Andy Lutomirski <luto@kernel.org> | |
24 | Cc: Borislav Petkov <bp@alien8.de> | |
25 | Cc: Brian Gerst <brgerst@gmail.com> | |
26 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
27 | Cc: H. Peter Anvin <hpa@zytor.com> | |
28 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
29 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
30 | Cc: Peter Zijlstra <peterz@infradead.org> | |
31 | Cc: Steven Rostedt <rostedt@goodmis.org> | |
32 | Link: http://lkml.kernel.org/r/20170828064957.861974317@linutronix.de | |
33 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
34 | (cherry picked from commit 64b163fab684e3de47aa8db6cc08ae7d2e194373) | |
35 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
36 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
37 | (cherry picked from commit 587719b1926757eb7531e0631d63fb93cd60d0d3) | |
38 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
39 | --- | |
40 | arch/x86/include/asm/desc.h | 45 ++++++++++++++----------------- | |
41 | arch/x86/include/asm/desc_defs.h | 57 ++++++++++++++++++++++++++-------------- | |
42 | arch/x86/kvm/vmx.c | 2 +- | |
43 | arch/x86/xen/enlighten_pv.c | 12 ++++----- | |
44 | 4 files changed, 63 insertions(+), 53 deletions(-) | |
45 | ||
46 | diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h | |
47 | index d0a21b12dd58..57e502a4e92f 100644 | |
48 | --- a/arch/x86/include/asm/desc.h | |
49 | +++ b/arch/x86/include/asm/desc.h | |
50 | @@ -83,33 +83,25 @@ static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu) | |
51 | return per_cpu_ptr_to_phys(get_cpu_gdt_rw(cpu)); | |
52 | } | |
53 | ||
54 | -#ifdef CONFIG_X86_64 | |
55 | - | |
56 | static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, | |
57 | unsigned dpl, unsigned ist, unsigned seg) | |
58 | { | |
59 | - gate->offset_low = PTR_LOW(func); | |
60 | + gate->offset_low = (u16) func; | |
61 | + gate->bits.p = 1; | |
62 | + gate->bits.dpl = dpl; | |
63 | + gate->bits.zero = 0; | |
64 | + gate->bits.type = type; | |
65 | + gate->offset_middle = (u16) (func >> 16); | |
66 | +#ifdef CONFIG_X86_64 | |
67 | gate->segment = __KERNEL_CS; | |
68 | - gate->ist = ist; | |
69 | - gate->p = 1; | |
70 | - gate->dpl = dpl; | |
71 | - gate->zero0 = 0; | |
72 | - gate->zero1 = 0; | |
73 | - gate->type = type; | |
74 | - gate->offset_middle = PTR_MIDDLE(func); | |
75 | - gate->offset_high = PTR_HIGH(func); | |
76 | -} | |
77 | - | |
78 | + gate->bits.ist = ist; | |
79 | + gate->reserved = 0; | |
80 | + gate->offset_high = (u32) (func >> 32); | |
81 | #else | |
82 | -static inline void pack_gate(gate_desc *gate, unsigned char type, | |
83 | - unsigned long base, unsigned dpl, unsigned flags, | |
84 | - unsigned short seg) | |
85 | -{ | |
86 | - gate->a = (seg << 16) | (base & 0xffff); | |
87 | - gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8); | |
88 | -} | |
89 | - | |
90 | + gate->segment = seg; | |
91 | + gate->bits.ist = 0; | |
92 | #endif | |
93 | +} | |
94 | ||
95 | static inline int desc_empty(const void *ptr) | |
96 | { | |
97 | @@ -185,7 +177,8 @@ static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, | |
98 | } | |
99 | ||
100 | ||
101 | -static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned type, unsigned size) | |
102 | +static inline void set_tssldt_descriptor(void *d, unsigned long addr, | |
103 | + unsigned type, unsigned size) | |
104 | { | |
105 | #ifdef CONFIG_X86_64 | |
106 | struct ldttss_desc64 *desc = d; | |
107 | @@ -193,13 +186,13 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned t | |
108 | memset(desc, 0, sizeof(*desc)); | |
109 | ||
110 | desc->limit0 = size & 0xFFFF; | |
111 | - desc->base0 = PTR_LOW(addr); | |
112 | - desc->base1 = PTR_MIDDLE(addr) & 0xFF; | |
113 | + desc->base0 = (u16) addr; | |
114 | + desc->base1 = (addr >> 16) & 0xFF; | |
115 | desc->type = type; | |
116 | desc->p = 1; | |
117 | desc->limit1 = (size >> 16) & 0xF; | |
118 | - desc->base2 = (PTR_MIDDLE(addr) >> 8) & 0xFF; | |
119 | - desc->base3 = PTR_HIGH(addr); | |
120 | + desc->base2 = (addr >> 24) & 0xFF; | |
121 | + desc->base3 = (u32) (addr >> 32); | |
122 | #else | |
123 | pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0); | |
124 | #endif | |
125 | diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h | |
126 | index 49265345d4d2..d684bee8a59a 100644 | |
127 | --- a/arch/x86/include/asm/desc_defs.h | |
128 | +++ b/arch/x86/include/asm/desc_defs.h | |
129 | @@ -47,20 +47,6 @@ enum { | |
130 | GATE_TASK = 0x5, | |
131 | }; | |
132 | ||
133 | -/* 16byte gate */ | |
134 | -struct gate_struct64 { | |
135 | - u16 offset_low; | |
136 | - u16 segment; | |
137 | - unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; | |
138 | - u16 offset_middle; | |
139 | - u32 offset_high; | |
140 | - u32 zero1; | |
141 | -} __attribute__((packed)); | |
142 | - | |
143 | -#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF) | |
144 | -#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF) | |
145 | -#define PTR_HIGH(x) ((unsigned long long)(x) >> 32) | |
146 | - | |
147 | enum { | |
148 | DESC_TSS = 0x9, | |
149 | DESC_LDT = 0x2, | |
150 | @@ -77,20 +63,51 @@ struct ldttss_desc64 { | |
151 | u32 zero1; | |
152 | } __attribute__((packed)); | |
153 | ||
154 | + | |
155 | #ifdef CONFIG_X86_64 | |
156 | -typedef struct gate_struct64 gate_desc; | |
157 | typedef struct ldttss_desc64 ldt_desc; | |
158 | typedef struct ldttss_desc64 tss_desc; | |
159 | -#define gate_offset(g) ((g).offset_low | ((unsigned long)(g).offset_middle << 16) | ((unsigned long)(g).offset_high << 32)) | |
160 | -#define gate_segment(g) ((g).segment) | |
161 | #else | |
162 | -typedef struct desc_struct gate_desc; | |
163 | typedef struct desc_struct ldt_desc; | |
164 | typedef struct desc_struct tss_desc; | |
165 | -#define gate_offset(g) (((g).b & 0xffff0000) | ((g).a & 0x0000ffff)) | |
166 | -#define gate_segment(g) ((g).a >> 16) | |
167 | #endif | |
168 | ||
169 | +struct idt_bits { | |
170 | + u16 ist : 3, | |
171 | + zero : 5, | |
172 | + type : 5, | |
173 | + dpl : 2, | |
174 | + p : 1; | |
175 | +} __attribute__((packed)); | |
176 | + | |
177 | +struct gate_struct { | |
178 | + u16 offset_low; | |
179 | + u16 segment; | |
180 | + struct idt_bits bits; | |
181 | + u16 offset_middle; | |
182 | +#ifdef CONFIG_X86_64 | |
183 | + u32 offset_high; | |
184 | + u32 reserved; | |
185 | +#endif | |
186 | +} __attribute__((packed)); | |
187 | + | |
188 | +typedef struct gate_struct gate_desc; | |
189 | + | |
190 | +static inline unsigned long gate_offset(const gate_desc *g) | |
191 | +{ | |
192 | +#ifdef CONFIG_X86_64 | |
193 | + return g->offset_low | ((unsigned long)g->offset_middle << 16) | | |
194 | + ((unsigned long) g->offset_high << 32); | |
195 | +#else | |
196 | + return g->offset_low | ((unsigned long)g->offset_middle << 16); | |
197 | +#endif | |
198 | +} | |
199 | + | |
200 | +static inline unsigned long gate_segment(const gate_desc *g) | |
201 | +{ | |
202 | + return g->segment; | |
203 | +} | |
204 | + | |
205 | struct desc_ptr { | |
206 | unsigned short size; | |
207 | unsigned long address; | |
208 | diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c | |
209 | index a2c95522ac99..7b447d126d17 100644 | |
210 | --- a/arch/x86/kvm/vmx.c | |
211 | +++ b/arch/x86/kvm/vmx.c | |
212 | @@ -8838,7 +8838,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) | |
213 | ||
214 | vector = exit_intr_info & INTR_INFO_VECTOR_MASK; | |
215 | desc = (gate_desc *)vmx->host_idt_base + vector; | |
216 | - entry = gate_offset(*desc); | |
217 | + entry = gate_offset(desc); | |
218 | asm volatile( | |
219 | #ifdef CONFIG_X86_64 | |
220 | "mov %%" _ASM_SP ", %[sp]\n\t" | |
221 | diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c | |
222 | index 6c279c8f0a0e..49ee3315b9f7 100644 | |
223 | --- a/arch/x86/xen/enlighten_pv.c | |
224 | +++ b/arch/x86/xen/enlighten_pv.c | |
225 | @@ -591,12 +591,12 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, | |
226 | { | |
227 | unsigned long addr; | |
228 | ||
229 | - if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) | |
230 | + if (val->bits.type != GATE_TRAP && val->bits.type != GATE_INTERRUPT) | |
231 | return 0; | |
232 | ||
233 | info->vector = vector; | |
234 | ||
235 | - addr = gate_offset(*val); | |
236 | + addr = gate_offset(val); | |
237 | #ifdef CONFIG_X86_64 | |
238 | /* | |
239 | * Look for known traps using IST, and substitute them | |
240 | @@ -629,16 +629,16 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, | |
241 | ; | |
242 | else { | |
243 | /* Some other trap using IST? */ | |
244 | - if (WARN_ON(val->ist != 0)) | |
245 | + if (WARN_ON(val->bits.ist != 0)) | |
246 | return 0; | |
247 | } | |
248 | #endif /* CONFIG_X86_64 */ | |
249 | info->address = addr; | |
250 | ||
251 | - info->cs = gate_segment(*val); | |
252 | - info->flags = val->dpl; | |
253 | + info->cs = gate_segment(val); | |
254 | + info->flags = val->bits.dpl; | |
255 | /* interrupt gates clear IF */ | |
256 | - if (val->type == GATE_INTERRUPT) | |
257 | + if (val->bits.type == GATE_INTERRUPT) | |
258 | info->flags |= 1 << 2; | |
259 | ||
260 | return 1; | |
261 | -- | |
262 | 2.14.2 | |
263 |