Commit cc801833 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Thomas Gleixner

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: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/92b2975459dfe5929ecf34c3896ad920bd9e3f2d.1593795633.git.luto@kernel.org
parent 13cbc0cd
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pgtable_areas.h> #include <asm/pgtable_areas.h>
#include <xen/xen.h>
/* This is a multiple of PAGE_SIZE. */ /* This is a multiple of PAGE_SIZE. */
#define LDT_SLOT_STRIDE (LDT_ENTRIES * LDT_ENTRY_SIZE) #define LDT_SLOT_STRIDE (LDT_ENTRIES * LDT_ENTRY_SIZE)
...@@ -543,6 +545,37 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount) ...@@ -543,6 +545,37 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount)
return bytecount; return bytecount;
} }
static bool allow_16bit_segments(void)
{
if (!IS_ENABLED(CONFIG_X86_16BIT))
return false;
#ifdef CONFIG_XEN_PV
/*
* Xen PV does not implement ESPFIX64, which means that 16-bit
* segments will not work correctly. Until either Xen PV implements
* ESPFIX64 and can signal this fact to the guest or unless someone
* provides compelling evidence that allowing broken 16-bit segments
* is worthwhile, disallow 16-bit segments under Xen PV.
*/
if (xen_pv_domain()) {
static DEFINE_MUTEX(xen_warning);
static bool warned;
mutex_lock(&xen_warning);
if (!warned) {
pr_info("Warning: 16-bit segments do not work correctly in a Xen PV guest\n");
warned = true;
}
mutex_unlock(&xen_warning);
return false;
}
#endif
return true;
}
static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
...@@ -574,7 +607,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) ...@@ -574,7 +607,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
/* The user wants to clear the entry. */ /* The user wants to clear the entry. */
memset(&ldt, 0, sizeof(ldt)); memset(&ldt, 0, sizeof(ldt));
} else { } else {
if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) { if (!ldt_info.seg_32bit && !allow_16bit_segments()) {
error = -EINVAL; error = -EINVAL;
goto out; goto out;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment