Merge tag 'x86-urgent-2020-07-05' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / arch / x86 / kernel / ldt.c
index 8748321c448674b0dc16a09d1f09ce7850bae15a..34e918ad34d4ce00cdc155146529ce972f1d8f15 100644 (file)
@@ -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;
                }