| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- From 34aa933a9bce5fb9c88e6ed98b268cbf058e51eb Mon Sep 17 00:00:00 2001
- From: Andy Lutomirski <[email protected]>
- Date: Wed, 26 Jul 2017 07:16:30 -0700
- Subject: [PATCH 038/242] x86/ldt/64: Refresh DS and ES when modify_ldt changes
- an entry
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- On x86_32, modify_ldt() implicitly refreshes the cached DS and ES
- segments because they are refreshed on return to usermode.
- On x86_64, they're not refreshed on return to usermode. To improve
- determinism and match x86_32's behavior, refresh them when we update
- the LDT.
- This avoids a situation in which the DS points to a descriptor that is
- changed but the old cached segment persists until the next reschedule.
- If this happens, then the user-visible state will change
- nondeterministically some time after modify_ldt() returns, which is
- unfortunate.
- Signed-off-by: Andy Lutomirski <[email protected]>
- Cc: Borislav Petkov <[email protected]>
- Cc: Chang Seok <[email protected]>
- Cc: Linus Torvalds <[email protected]>
- Cc: Peter Zijlstra <[email protected]>
- Cc: Thomas Gleixner <[email protected]>
- Signed-off-by: Ingo Molnar <[email protected]>
- (cherry picked from commit a632375764aa25c97b78beb56c71b0ba59d1cf83)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit 295cb0b06150958ec84ee4b8844ef7e389e22c4e)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/kernel/ldt.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
- diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
- index a870910c8565..f0e64db18ac8 100644
- --- a/arch/x86/kernel/ldt.c
- +++ b/arch/x86/kernel/ldt.c
- @@ -21,6 +21,25 @@
- #include <asm/mmu_context.h>
- #include <asm/syscalls.h>
-
- +static void refresh_ldt_segments(void)
- +{
- +#ifdef CONFIG_X86_64
- + unsigned short sel;
- +
- + /*
- + * Make sure that the cached DS and ES descriptors match the updated
- + * LDT.
- + */
- + savesegment(ds, sel);
- + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT)
- + loadsegment(ds, sel);
- +
- + savesegment(es, sel);
- + if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT)
- + loadsegment(es, sel);
- +#endif
- +}
- +
- /* context.lock is held for us, so we don't need any locking. */
- static void flush_ldt(void *__mm)
- {
- @@ -32,6 +51,8 @@ static void flush_ldt(void *__mm)
-
- pc = &mm->context;
- set_ldt(pc->ldt->entries, pc->ldt->nr_entries);
- +
- + refresh_ldt_segments();
- }
-
- /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
- --
- 2.14.2
|