mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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 <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/92b2975459dfe5929ecf34c3896ad920bd9e3f2d.1593795633.git.luto@kernel.org
This commit is contained in:
parent
13cbc0cd4a
commit
cc801833a1
@ -29,6 +29,8 @@
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgtable_areas.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
||||
/* This is a multiple of PAGE_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)
|
||||
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)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
@ -574,7 +607,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
|
||||
/* The user wants to clear the entry. */
|
||||
memset(&ldt, 0, sizeof(ldt));
|
||||
} else {
|
||||
if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
|
||||
if (!ldt_info.seg_32bit && !allow_16bit_segments()) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user