]>
Commit | Line | Data |
---|---|---|
59d5af67 | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
321d628a FG |
2 | From: Andy Lutomirski <luto@kernel.org> |
3 | Date: Wed, 26 Jul 2017 07:16:30 -0700 | |
59d5af67 FG |
4 | Subject: [PATCH] x86/ldt/64: Refresh DS and ES when modify_ldt changes an |
5 | entry | |
321d628a FG |
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 | On x86_32, modify_ldt() implicitly refreshes the cached DS and ES | |
13 | segments because they are refreshed on return to usermode. | |
14 | ||
15 | On x86_64, they're not refreshed on return to usermode. To improve | |
16 | determinism and match x86_32's behavior, refresh them when we update | |
17 | the LDT. | |
18 | ||
19 | This avoids a situation in which the DS points to a descriptor that is | |
20 | changed but the old cached segment persists until the next reschedule. | |
21 | If this happens, then the user-visible state will change | |
22 | nondeterministically some time after modify_ldt() returns, which is | |
23 | unfortunate. | |
24 | ||
25 | Signed-off-by: Andy Lutomirski <luto@kernel.org> | |
26 | Cc: Borislav Petkov <bpetkov@suse.de> | |
27 | Cc: Chang Seok <chang.seok.bae@intel.com> | |
28 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
29 | Cc: Peter Zijlstra <peterz@infradead.org> | |
30 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
31 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
32 | (cherry picked from commit a632375764aa25c97b78beb56c71b0ba59d1cf83) | |
33 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
34 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
35 | (cherry picked from commit 295cb0b06150958ec84ee4b8844ef7e389e22c4e) | |
36 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
37 | --- | |
38 | arch/x86/kernel/ldt.c | 21 +++++++++++++++++++++ | |
39 | 1 file changed, 21 insertions(+) | |
40 | ||
41 | diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c | |
42 | index a870910c8565..f0e64db18ac8 100644 | |
43 | --- a/arch/x86/kernel/ldt.c | |
44 | +++ b/arch/x86/kernel/ldt.c | |
45 | @@ -21,6 +21,25 @@ | |
46 | #include <asm/mmu_context.h> | |
47 | #include <asm/syscalls.h> | |
48 | ||
49 | +static void refresh_ldt_segments(void) | |
50 | +{ | |
51 | +#ifdef CONFIG_X86_64 | |
52 | + unsigned short sel; | |
53 | + | |
54 | + /* | |
55 | + * Make sure that the cached DS and ES descriptors match the updated | |
56 | + * LDT. | |
57 | + */ | |
58 | + savesegment(ds, sel); | |
59 | + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) | |
60 | + loadsegment(ds, sel); | |
61 | + | |
62 | + savesegment(es, sel); | |
63 | + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) | |
64 | + loadsegment(es, sel); | |
65 | +#endif | |
66 | +} | |
67 | + | |
68 | /* context.lock is held for us, so we don't need any locking. */ | |
69 | static void flush_ldt(void *__mm) | |
70 | { | |
71 | @@ -32,6 +51,8 @@ static void flush_ldt(void *__mm) | |
72 | ||
73 | pc = &mm->context; | |
74 | set_ldt(pc->ldt->entries, pc->ldt->nr_entries); | |
75 | + | |
76 | + refresh_ldt_segments(); | |
77 | } | |
78 | ||
79 | /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */ | |
80 | -- | |
81 | 2.14.2 | |
82 |