mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
memory: split and tighten maximum order permitted in memops
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: 4a578b316e
master date: 2015-12-08 14:00:33 +0100
This commit is contained in:
1 parent
602506b3ef
commit
dcbb31d041
6 files changed
+74
-27
No files matched your search
@@ -653,6 +653,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>`
|
||||
|
||||
|
||||
+55
-17
@@ -46,6 +46,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;
|
||||
@@ -58,7 +102,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++ )
|
||||
@@ -103,8 +147,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++ )
|
||||
@@ -269,7 +313,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++ )
|
||||
@@ -334,13 +378,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) ||
|
||||
@@ -359,16 +407,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;
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
#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
|
||||
|
||||
|
||||
@@ -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__ */
|
||||