Skip to content

Commit cc80183

Browse files
amlutoKAGA-KOKO
authored andcommitted
x86/ldt: Disable 16-bit segments on Xen PV
Xen PV doesn't implement ESPFIX64, so they don't work right. Disable them. Also print a warning the first time anyone tries to use a 16-bit segment on a Xen PV guest that would otherwise allow it to help people diagnose this change in behavior. This gets us closer to having all x86 selftests pass on Xen PV. Signed-off-by: Andy Lutomirski <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/92b2975459dfe5929ecf34c3896ad920bd9e3f2d.1593795633.git.luto@kernel.org
1 parent 13cbc0c commit cc80183

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

arch/x86/kernel/ldt.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <asm/mmu_context.h>
3030
#include <asm/pgtable_areas.h>
3131

32+
#include <xen/xen.h>
33+
3234
/* This is a multiple of PAGE_SIZE. */
3335
#define LDT_SLOT_STRIDE (LDT_ENTRIES * LDT_ENTRY_SIZE)
3436

@@ -543,6 +545,37 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount)
543545
return bytecount;
544546
}
545547

548+
static bool allow_16bit_segments(void)
549+
{
550+
if (!IS_ENABLED(CONFIG_X86_16BIT))
551+
return false;
552+
553+
#ifdef CONFIG_XEN_PV
554+
/*
555+
* Xen PV does not implement ESPFIX64, which means that 16-bit
556+
* segments will not work correctly. Until either Xen PV implements
557+
* ESPFIX64 and can signal this fact to the guest or unless someone
558+
* provides compelling evidence that allowing broken 16-bit segments
559+
* is worthwhile, disallow 16-bit segments under Xen PV.
560+
*/
561+
if (xen_pv_domain()) {
562+
static DEFINE_MUTEX(xen_warning);
563+
static bool warned;
564+
565+
mutex_lock(&xen_warning);
566+
if (!warned) {
567+
pr_info("Warning: 16-bit segments do not work correctly in a Xen PV guest\n");
568+
warned = true;
569+
}
570+
mutex_unlock(&xen_warning);
571+
572+
return false;
573+
}
574+
#endif
575+
576+
return true;
577+
}
578+
546579
static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
547580
{
548581
struct mm_struct *mm = current->mm;
@@ -574,7 +607,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
574607
/* The user wants to clear the entry. */
575608
memset(&ldt, 0, sizeof(ldt));
576609
} else {
577-
if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
610+
if (!ldt_info.seg_32bit && !allow_16bit_segments()) {
578611
error = -EINVAL;
579612
goto out;
580613
}

0 commit comments

Comments
 (0)