]> xenbits.xensource.com Git - xen.git/commitdiff
memory: split and tighten maximum order permitted in memops
authorJan Beulich <jbeulich@suse.com>
Tue, 8 Dec 2015 13:12:50 +0000 (14:12 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 8 Dec 2015 13:12:50 +0000 (14:12 +0100)
Introduce and enforce separate limits for ordinary DomU, DomU with
pass-through device(s), control domain, and hardware domain.

The DomU defaults were determined based on what so far was allowed by
multipage_allocation_permitted().

The x86 hwdom default was chosen based on linux-2.6.18-xen.hg c/s
1102:82782f1361a9 indicating 2Mb is not enough, plus some slack.

The ARM hwdom default was chosen to allow 2Mb (order-9) mappings, plus
a little bit of slack.

This is CVE-2015-8338 / XSA-158.

Reported-by: Julien Grall <julien.grall@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
master commit: 4a578b316eb98975374d88f28904acf13dbcfac2
master date: 2015-12-08 14:00:33 +0100

docs/misc/xen-command-line.markdown
xen/common/memory.c
xen/include/asm-arm/config.h
xen/include/asm-arm/iocap.h
xen/include/asm-x86/config.h
xen/include/asm-x86/iocap.h

index 963936c50fc44a9bf5fd1bbf1d2bb789eafcab77..f1f70fbd9ddc4cb3f33f9b5101efacc49b4f0c58 100644 (file)
@@ -612,6 +612,17 @@ which data structures should be deliberately allocated in low memory,
 so the crash kernel may find find them.  Should be used in combination
 with **crashinfo_maxaddr**.
 
+### memop-max-order
+> `= [<domU>][,[<ctldom>][,[<hwdom>][,<ptdom>]]]`
+
+> x86 default: `9,18,12,12`
+> ARM default: `9,18,10,10`
+
+Change the maximum order permitted for allocation (or allocation-like)
+requests issued by the various kinds of domains (in this order:
+ordinary DomU, control domain, hardware domain, and - when supported
+by the platform - DomU with pass-through device assigned).
+
 ### max\_cstate
 > `= <integer>`
 
index d2623d4ef66fd213e3e0907bda1548501d20f0ac..9859ec815c68ad4b16e7bed61bf277dc1a54ec9a 100644 (file)
@@ -42,6 +42,50 @@ struct memop_args {
     int          preempted;  /* Was the hypercall preempted? */
 };
 
+#ifndef CONFIG_CTLDOM_MAX_ORDER
+#define CONFIG_CTLDOM_MAX_ORDER CONFIG_PAGEALLOC_MAX_ORDER
+#endif
+#ifndef CONFIG_PTDOM_MAX_ORDER
+#define CONFIG_PTDOM_MAX_ORDER CONFIG_HWDOM_MAX_ORDER
+#endif
+
+static unsigned int __read_mostly domu_max_order = CONFIG_DOMU_MAX_ORDER;
+static unsigned int __read_mostly ctldom_max_order = CONFIG_CTLDOM_MAX_ORDER;
+static unsigned int __read_mostly hwdom_max_order = CONFIG_HWDOM_MAX_ORDER;
+#ifdef HAS_PASSTHROUGH
+static unsigned int __read_mostly ptdom_max_order = CONFIG_PTDOM_MAX_ORDER;
+#else
+# define ptdom_max_order domu_max_order
+#endif
+static void __init parse_max_order(const char *s)
+{
+    if ( *s != ',' )
+        domu_max_order = simple_strtoul(s, &s, 0);
+    if ( *s == ',' && *++s != ',' )
+        ctldom_max_order = simple_strtoul(s, &s, 0);
+    if ( *s == ',' && *++s != ',' )
+        hwdom_max_order = simple_strtoul(s, &s, 0);
+#ifdef HAS_PASSTHROUGH
+    if ( *s == ',' && *++s != ',' )
+        ptdom_max_order = simple_strtoul(s, &s, 0);
+#endif
+}
+custom_param("memop-max-order", parse_max_order);
+
+static unsigned int max_order(const struct domain *d)
+{
+    unsigned int order = cache_flush_permitted(d) ? domu_max_order
+                                                  : ptdom_max_order;
+
+    if ( is_control_domain(d) && order < ctldom_max_order )
+        order = ctldom_max_order;
+
+    if ( is_hardware_domain(d) && order < hwdom_max_order )
+        order = hwdom_max_order;
+
+    return min(order, MAX_ORDER + 0U);
+}
+
 static void increase_reservation(struct memop_args *a)
 {
     struct page_info *page;
@@ -54,7 +98,7 @@ static void increase_reservation(struct memop_args *a)
                                      a->nr_extents-1) )
         return;
 
-    if ( !multipage_allocation_permitted(current->domain, a->extent_order) )
+    if ( a->extent_order > max_order(current->domain) )
         return;
 
     for ( i = a->nr_done; i < a->nr_extents; i++ )
@@ -99,8 +143,8 @@ static void populate_physmap(struct memop_args *a)
                                      a->nr_extents-1) )
         return;
 
-    if ( a->memflags & MEMF_populate_on_demand ? a->extent_order > MAX_ORDER :
-         !multipage_allocation_permitted(current->domain, a->extent_order) )
+    if ( a->extent_order > (a->memflags & MEMF_populate_on_demand ? MAX_ORDER :
+                            max_order(current->domain)) )
         return;
 
     for ( i = a->nr_done; i < a->nr_extents; i++ )
@@ -237,7 +281,7 @@ static void decrease_reservation(struct memop_args *a)
 
     if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done,
                                      a->nr_extents-1) ||
-         a->extent_order > MAX_ORDER )
+         a->extent_order > max_order(current->domain) )
         return;
 
     for ( i = a->nr_done; i < a->nr_extents; i++ )
@@ -295,13 +339,17 @@ static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
     if ( copy_from_guest(&exch, arg, 1) )
         return -EFAULT;
 
+    if ( max(exch.in.extent_order, exch.out.extent_order) >
+         max_order(current->domain) )
+    {
+        rc = -EPERM;
+        goto fail_early;
+    }
+
     /* Various sanity checks. */
     if ( (exch.nr_exchanged > exch.in.nr_extents) ||
          /* Input and output domain identifiers match? */
          (exch.in.domid != exch.out.domid) ||
-         /* Extent orders are sensible? */
-         (exch.in.extent_order > MAX_ORDER) ||
-         (exch.out.extent_order > MAX_ORDER) ||
          /* Sizes of input and output lists do not overflow a long? */
          ((~0UL >> exch.in.extent_order) < exch.in.nr_extents) ||
          ((~0UL >> exch.out.extent_order) < exch.out.nr_extents) ||
@@ -320,16 +368,6 @@ static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
         goto fail_early;
     }
 
-    /* Only privileged guests can allocate multi-page contiguous extents. */
-    if ( !multipage_allocation_permitted(current->domain,
-                                         exch.in.extent_order) ||
-         !multipage_allocation_permitted(current->domain,
-                                         exch.out.extent_order) )
-    {
-        rc = -EPERM;
-        goto fail_early;
-    }
-
     if ( exch.in.extent_order <= exch.out.extent_order )
     {
         in_chunk_order  = exch.out.extent_order - exch.in.extent_order;
index e3cfaf1cf459a40e7463f9ddb8f8f22d1eb407bc..5d32ed85edbb1f2e4ac3fd286094e6f57457854d 100644 (file)
 
 #define CONFIG_VIDEO 1
 
+#define CONFIG_PAGEALLOC_MAX_ORDER 18
+#define CONFIG_DOMU_MAX_ORDER      9
+#define CONFIG_HWDOM_MAX_ORDER     10
+
 #define OPT_CONSOLE_STR "dtuart"
 
 #ifdef MAX_PHYS_CPUS
index 22cfa4155aa6c96ff429fb27883f4cc605d95bb1..276fefbc59b9f9c583e3827e104062c60292123f 100644 (file)
@@ -4,10 +4,6 @@
 #define cache_flush_permitted(d)                        \
     (!rangeset_is_empty((d)->iomem_caps))
 
-#define multipage_allocation_permitted(d, order)        \
-    (((order) <= 9) || /* allow 2MB superpages */       \
-     !rangeset_is_empty((d)->iomem_caps))
-
 #endif
 
 /*
index 9d76a04e4b4c557d1320fcd6907284c7c66f7638..22c6298e9ad4ec019ba246c0e0aaa4b2b7b45dd8 100644 (file)
 #define CONFIG_NUMA 1
 #define CONFIG_DISCONTIGMEM 1
 #define CONFIG_NUMA_EMU 1
-#define CONFIG_PAGEALLOC_MAX_ORDER (2 * PAGETABLE_ORDER)
 #define CONFIG_DOMAIN_PAGE 1
 
+#define CONFIG_PAGEALLOC_MAX_ORDER (2 * PAGETABLE_ORDER)
+#define CONFIG_DOMU_MAX_ORDER      PAGETABLE_ORDER
+#define CONFIG_HWDOM_MAX_ORDER     12
+
 /* Intel P4 currently has largest cache line (L2 line size is 128 bytes). */
 #define CONFIG_X86_L1_CACHE_SHIFT 7
 
index 591ae1736875614717aee4c81528f0bc0ae3c63e..eee47228d4a583faabf24751e498b352020ed0cd 100644 (file)
@@ -18,9 +18,4 @@
     (!rangeset_is_empty((d)->iomem_caps) ||             \
      !rangeset_is_empty((d)->arch.ioport_caps))
 
-#define multipage_allocation_permitted(d, order)        \
-    (((order) <= 9) || /* allow 2MB superpages */       \
-     !rangeset_is_empty((d)->iomem_caps) ||             \
-     !rangeset_is_empty((d)->arch.ioport_caps))
-
 #endif /* __X86_IOCAP_H__ */