[PATCH] x86/PV: consolidate LDT checks

Jan Beulich posted 1 patch 7 months, 3 weeks ago
Failed in applying to current master (apply log)
[PATCH] x86/PV: consolidate LDT checks
Posted by Jan Beulich 7 months, 3 weeks ago
Consolidate all hypercall time checking into a single helper function,
checking only static properties. The dynamic properties are already
taken care of by the __addr_ok() check in guest_get_eff_kern_l1e(),
used by pv_map_ldt_shadow_page(), in a formally more "precise" manner
(accounting for the offset into the table).

Signed-off-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1081,7 +1081,6 @@ int arch_set_info_guest(
             if ( !is_canonical_address(c.nat->user_regs.rip) ||
                  !is_canonical_address(c.nat->user_regs.rsp) ||
                  !is_canonical_address(c.nat->kernel_sp) ||
-                 (c.nat->ldt_ents && !is_canonical_address(c.nat->ldt_base)) ||
                  !is_canonical_address(c.nat->fs_base) ||
                  !is_canonical_address(c.nat->gs_base_kernel) ||
                  !is_canonical_address(c.nat->gs_base_user) ||
@@ -1100,9 +1099,6 @@ int arch_set_info_guest(
                     return -EINVAL;
                 fixup_guest_code_selector(d, c.nat->trap_ctxt[i].cs);
             }
-
-            if ( !__addr_ok(c.nat->ldt_base) )
-                return -EINVAL;
         }
 #ifdef CONFIG_COMPAT
         else
@@ -1119,8 +1115,7 @@ int arch_set_info_guest(
 #endif
 
         /* LDT safety checks. */
-        if ( ((c(ldt_base) & (PAGE_SIZE - 1)) != 0) ||
-             (c(ldt_ents) > 8192) )
+        if ( !pv_is_valid_ldt(c(ldt_base), c(ldt_ents)) )
             return -EINVAL;
 
         v->arch.pv.vgc_flags = flags;
--- a/xen/arch/x86/include/asm/pv/mm.h
+++ b/xen/arch/x86/include/asm/pv/mm.h
@@ -46,4 +46,14 @@ static inline bool pv_destroy_ldt(struct
 
 #endif
 
+static inline bool pv_is_valid_ldt(unsigned long base, unsigned int ents)
+{
+    if ( !ents )
+        return true;
+
+    return !(base & (PAGE_SIZE - 1)) && ents <= 8192 &&
+           is_canonical_address(base) &&
+           is_canonical_address(base + ents * 8 - 1);
+}
+
 #endif /* __X86_PV_MM_H__ */
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -3800,8 +3800,7 @@ long do_mmuext_op(
                 rc = -EPERM;
             else if ( paging_mode_external(currd) )
                 rc = -EINVAL;
-            else if ( (ents > 8192) ||
-                      (ents && ((ptr & (PAGE_SIZE - 1)) || !__addr_ok(ptr))) )
+            else if ( !pv_is_valid_ldt(ptr, ents) )
             {
                 gdprintk(XENLOG_WARNING,
                          "Bad args to SET_LDT: ptr=%lx, ents=%x\n", ptr, ents);