Commit-ID: a632375764aa25c97b78beb56c71b0ba59d1cf83 Gitweb: http://git.kernel.org/tip/a632375764aa25c97b78beb56c71b0ba59d1cf83 Author: Andy Lutomirski <luto@xxxxxxxxxx> AuthorDate: Wed, 26 Jul 2017 07:16:30 -0700 Committer: Ingo Molnar <mingo@xxxxxxxxxx> CommitDate: Thu, 27 Jul 2017 09:12:57 +0200 x86/ldt/64: Refresh DS and ES when modify_ldt changes an entry 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 <luto@xxxxxxxxxx> Cc: Borislav Petkov <bpetkov@xxxxxxx> Cc: Chang Seok <chang.seok.bae@xxxxxxxxx> Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx> --- 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 a870910..f0e64db 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. */ -- To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html
![]() |