* Xen Security Advisory 158 (CVE-2015-8338) - long running memory operations on ARM
@ 2015-12-08 12:01 Xen.org security team
0 siblings, 0 replies; 2+ messages in thread
From: Xen.org security team @ 2015-12-08 12:01 UTC (permalink / raw)
To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team
[-- Attachment #1: Type: text/plain, Size: 5104 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2015-8338 / XSA-158
version 3
long running memory operations on ARM
UPDATES IN VERSION 3
====================
Public release.
ISSUE DESCRIPTION
=================
Certain HYPERVISOR_memory_op subops take page order inputs, with so far
insufficient enforcement of limits thereof. In particular, for all of
XENMEM_increase_reservation, XENMEM_populate_physmap, and
XENMEM_exchange the order was limited to 9 only for guests without
physical devices assigned. Guests with assigned devices were allowed up
to order 18 (x86) or 20 (ARM). XENMEM_decrease_reservation enforced
only the latter, higher limit uniformly on all kinds of guests.
All of these operations involve loops over individual pages (possibly
nested, with only the iteration count of the innermost loop being of
interest here), resulting in iteration counts of up to 1 million on
ARM. Total execution time of these operations obviously depends on
system speed, but have been measured to get into the seconds range.
IMPACT
======
A malicious guest administrator can cause a denial of service.
Specifically, prevent use of a physical CPU for a significant period.
Other attacks, namely privilege escalation, cannot be ruled out.
If a host watchdog (Xen or dom0) is in use, this can lead to a
watchdog timeout and consequently a reboot of the host. If another,
innocent, guest, is configured with a watchdog, this issue can lead to
a reboot of such a guest.
VULNERABLE SYSTEMS
==================
All Xen versions supporting ARM are affected.
x86 versions of Xen are unaffected.
MITIGATION
==========
The vulnerability can be avoided if the guest kernel is controlled by
the host rather than guest administrator, provided that further steps
are taken to prevent the guest administrator from loading code into
the kernel (e.g. by disabling loadable modules etc) or from using
other mechanisms which allow them to run code at kernel privilege. On
ARM, controlling the guest's kernel may involve locking down the
bootloader.
Exposure may be limited by not passing through physical devices to
untrusted guests.
(However, where device pass-through is being used to enhance security,
for example, by disaggregating device drivers, users should not change
their configuration: moving the drivers from a separate domain, to
dom0, does NOT mitigate this vulnerability. Rather, it simply
recategorises the additional exposure, regarding it "as designed" and
therefore "not a bug". Users and vendors of disaggregated systems
should not change their configuration.)
CREDITS
=======
This issue was discovered by Julien Grall of Citrix.
RESOLUTION
==========
Applying the appropriate attached patch resolves this issue.
xsa158.patch xen-unstable, Xen 4.6.x, Xen 4.5.x
xsa158-4.4.patch Xen 4.4.x, Xen 4.3.x
$ sha256sum xsa158*
50d7431cbad8faa631e2057ddd795b880f79b96d126a0b83afef3eceacf0026d xsa158.patch
54b538905e66227bf7f326006a7c322bdf35c76ad8600ff462e61d6e2eab6f04 xsa158-4.4.patch
$
DEPLOYMENT DURING EMBARGO
=========================
Deployment of the PATCH (or others which are substantially similar) is
permitted during the embargo, even on public-facing systems with
untrusted guest users and administrators.
However deployment of the NO PASS-THROUGH partial MITIGATION is NOT
permitted (except where all the affected systems and VMs are
administered and used only by organisations which are members of the
Xen Project Security Issues Predisclosure List). Specifically,
deployment on public cloud systems is NOT permitted.
This is because altering the set of devices observable in a guest in
connection with a security issue would be a user-visible change which
could lead to the rediscovery of the vulnerability.
Deployment of the mitigation is permitted only AFTER the embargo ends.
Also: Distribution of updated software is prohibited (except to other
members of the predisclosure list).
Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.
(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable. This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)
For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iQEcBAEBAgAGBQJWZr8FAAoJEIP+FMlX6CvZS7UIAKtjK/KGZxAv3L38qTlldHhF
BAYuZvlDt4wJEKYd9wUbN5nqXAL23muKj+oOLjS4PRHnsNKAjyKicJEFDIpLGr9z
fLKqmWvxnDexP3tjiUqz5z8IOpGTMgFPPl9kosYXhBiQAIrrlTigL+umYSGlIsB1
MkLfW1ZST3H7eoBzNkFEpGsMTjAtnYJfYwZp2MLC8sbdNq04RWbiIqljEb61ULdi
CXAFoiVcDiNbRrT2LRFwfAIM2mtzi6Me0GUMmGrdsfg0rlmgxHVItPLEd8fZ1CTE
ChqUOCZfL9DH3zlBgqD+0oADxhfwbHHnsu2Mvy0MzgwTZ7zX+12eer89qwvtgwA=
=AIko
-----END PGP SIGNATURE-----
[-- Attachment #2: xsa158.patch --]
[-- Type: application/octet-stream, Size: 7650 bytes --]
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 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>
---
v2: Rename command line option to "memop-max-order". Clarify domain
kinds in command line option doc. Correct its syntax description.
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1029,6 +1029,17 @@ with **crashinfo_maxaddr**.
Specify the threshold below which Xen will inform dom0 that the quantity of
free memory is getting low. Specifying `0` will disable this notification.
+### 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>`
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -43,6 +43,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;
@@ -55,7 +99,7 @@ static void increase_reservation(struct
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++ )
@@ -100,8 +144,8 @@ static void populate_physmap(struct memo
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++ )
@@ -285,7 +329,7 @@ static void decrease_reservation(struct
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++ )
@@ -343,13 +387,17 @@ static long memory_exchange(XEN_GUEST_HA
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) ||
@@ -368,16 +416,6 @@ static long memory_exchange(XEN_GUEST_HA
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;
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -39,6 +39,10 @@
#define CONFIG_IRQ_HAS_MULTIPLE_ACTION 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
--- a/xen/include/asm-arm/iocap.h
+++ b/xen/include/asm-arm/iocap.h
@@ -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
/*
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -28,9 +28,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
--- a/xen/include/asm-x86/iocap.h
+++ b/xen/include/asm-x86/iocap.h
@@ -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__ */
[-- Attachment #3: xsa158-4.4.patch --]
[-- Type: application/octet-stream, Size: 7449 bytes --]
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 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>
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -653,6 +653,17 @@ which data structures should be delibera
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>`
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -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
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 memo
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
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_HA
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_HA
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;
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -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
--- a/xen/include/asm-arm/iocap.h
+++ b/xen/include/asm-arm/iocap.h
@@ -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
/*
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -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
--- a/xen/include/asm-x86/iocap.h
+++ b/xen/include/asm-x86/iocap.h
@@ -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__ */
[-- Attachment #4: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread* Xen Security Advisory 158 (CVE-2015-8338) - long running memory operations on ARM
@ 2015-12-10 13:55 Xen.org security team
0 siblings, 0 replies; 2+ messages in thread
From: Xen.org security team @ 2015-12-10 13:55 UTC (permalink / raw)
To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team
[-- Attachment #1: Type: text/plain, Size: 6029 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2015-8338 / XSA-158
version 4
long running memory operations on ARM
UPDATES IN VERSION 4
====================
Mention that the original patches had two problems, supplying an
incremental patch.
ISSUE DESCRIPTION
=================
Certain HYPERVISOR_memory_op subops take page order inputs, with so far
insufficient enforcement of limits thereof. In particular, for all of
XENMEM_increase_reservation, XENMEM_populate_physmap, and
XENMEM_exchange the order was limited to 9 only for guests without
physical devices assigned. Guests with assigned devices were allowed up
to order 18 (x86) or 20 (ARM). XENMEM_decrease_reservation enforced
only the latter, higher limit uniformly on all kinds of guests.
All of these operations involve loops over individual pages (possibly
nested, with only the iteration count of the innermost loop being of
interest here), resulting in iteration counts of up to 1 million on
ARM. Total execution time of these operations obviously depends on
system speed, but have been measured to get into the seconds range.
IMPACT
======
A malicious guest administrator can cause a denial of service.
Specifically, prevent use of a physical CPU for a significant period.
Other attacks, namely privilege escalation, cannot be ruled out.
If a host watchdog (Xen or dom0) is in use, this can lead to a
watchdog timeout and consequently a reboot of the host. If another,
innocent, guest, is configured with a watchdog, this issue can lead to
a reboot of such a guest.
VULNERABLE SYSTEMS
==================
All Xen versions supporting ARM are affected.
x86 versions of Xen are unaffected.
MITIGATION
==========
The vulnerability can be avoided if the guest kernel is controlled by
the host rather than guest administrator, provided that further steps
are taken to prevent the guest administrator from loading code into
the kernel (e.g. by disabling loadable modules etc) or from using
other mechanisms which allow them to run code at kernel privilege. On
ARM, controlling the guest's kernel may involve locking down the
bootloader.
Exposure may be limited by not passing through physical devices to
untrusted guests.
(However, where device pass-through is being used to enhance security,
for example, by disaggregating device drivers, users should not change
their configuration: moving the drivers from a separate domain, to
dom0, does NOT mitigate this vulnerability. Rather, it simply
recategorises the additional exposure, regarding it "as designed" and
therefore "not a bug". Users and vendors of disaggregated systems
should not change their configuration.)
CREDITS
=======
This issue was discovered by Julien Grall of Citrix.
RESOLUTION
==========
Applying the appropriate attached patch resolves this issue.
Note that the patches provided with previous versions of this advisory
had two problems:
- The bounding for ordinary DomU and DomU with pass-through devices(s)
was swapped. This would result in non-pass-through domains being able
to perform operations with larger than intended order. In the default
configuration this higher limit is not sufficient to reopen the
security issue. However, users of the new memop-max-order option
may be vulnerable, depending on the limits they specify.
- On 4.4 and earlier, the relevant patch does not compile on ARM.
The supplementary patch xsa158-fix.patch fixes these problems on all
listed versions.
In summary:
xsa158.patch } xen-unstable, Xen 4.6.x, Xen 4.5.x
xsa158-fix.patch } apply both patches
xsa158-4.4.patch } Xen 4.4.x, Xen 4.3.x
xsa158-fix.patch } apply both patches
$ sha256sum xsa158*
50d7431cbad8faa631e2057ddd795b880f79b96d126a0b83afef3eceacf0026d xsa158.patch
54b538905e66227bf7f326006a7c322bdf35c76ad8600ff462e61d6e2eab6f04 xsa158-4.4.patch
ab37e320bceeccc81285a6a72b92ed1292b69ddd8da5af94276b4b5cca4a0441 xsa158-fix.patch
$
DEPLOYMENT DURING EMBARGO
=========================
Deployment of the PATCH (or others which are substantially similar) is
permitted during the embargo, even on public-facing systems with
untrusted guest users and administrators.
However deployment of the NO PASS-THROUGH partial MITIGATION is NOT
permitted (except where all the affected systems and VMs are
administered and used only by organisations which are members of the
Xen Project Security Issues Predisclosure List). Specifically,
deployment on public cloud systems is NOT permitted.
This is because altering the set of devices observable in a guest in
connection with a security issue would be a user-visible change which
could lead to the rediscovery of the vulnerability.
Deployment of the mitigation is permitted only AFTER the embargo ends.
Also: Distribution of updated software is prohibited (except to other
members of the predisclosure list).
Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.
(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable. This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)
For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iQEcBAEBAgAGBQJWaYRSAAoJEIP+FMlX6CvZpvIH/A1r8mOX9Gvlz7rUonFVD5Lq
8SE4Ju4TwU9YA+sMZCpLInUC2UoVQGf/8bMWNvbB+yfnALDb5txC/ms8XEZVZWHk
tfum+lzmdolMsxGY2JvjRFuwoUZB1rTzcGe9pvH5y3KMKAo7dlN5+DSdym5zoQcZ
QqIiAjHj7UXC0Feg5tmRSAp5ht+yMD0rIGJ6/6fFzhdoPyLinzY1Bb12iJN6Xsd+
b7Vl7h80XU23JTviLpEZkx0cDykhzNWGZjsdQPmoDagVaxvahZPCVnefUIkeAHJZ
nGdm//cs/CHHBX7iTKlhN5/eDZLqb2etI9v2kRvXkcgEfHYpNgm5cowD4dvBf30=
=EDH5
-----END PGP SIGNATURE-----
[-- Attachment #2: xsa158.patch --]
[-- Type: application/octet-stream, Size: 7650 bytes --]
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 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>
---
v2: Rename command line option to "memop-max-order". Clarify domain
kinds in command line option doc. Correct its syntax description.
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1029,6 +1029,17 @@ with **crashinfo_maxaddr**.
Specify the threshold below which Xen will inform dom0 that the quantity of
free memory is getting low. Specifying `0` will disable this notification.
+### 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>`
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -43,6 +43,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;
@@ -55,7 +99,7 @@ static void increase_reservation(struct
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++ )
@@ -100,8 +144,8 @@ static void populate_physmap(struct memo
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++ )
@@ -285,7 +329,7 @@ static void decrease_reservation(struct
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++ )
@@ -343,13 +387,17 @@ static long memory_exchange(XEN_GUEST_HA
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) ||
@@ -368,16 +416,6 @@ static long memory_exchange(XEN_GUEST_HA
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;
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -39,6 +39,10 @@
#define CONFIG_IRQ_HAS_MULTIPLE_ACTION 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
--- a/xen/include/asm-arm/iocap.h
+++ b/xen/include/asm-arm/iocap.h
@@ -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
/*
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -28,9 +28,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
--- a/xen/include/asm-x86/iocap.h
+++ b/xen/include/asm-x86/iocap.h
@@ -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__ */
[-- Attachment #3: xsa158-4.4.patch --]
[-- Type: application/octet-stream, Size: 7449 bytes --]
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 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>
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -653,6 +653,17 @@ which data structures should be delibera
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>`
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -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
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 memo
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
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_HA
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_HA
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;
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -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
--- a/xen/include/asm-arm/iocap.h
+++ b/xen/include/asm-arm/iocap.h
@@ -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
/*
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -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
--- a/xen/include/asm-x86/iocap.h
+++ b/xen/include/asm-x86/iocap.h
@@ -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__ */
[-- Attachment #4: xsa158-fix.patch --]
[-- Type: application/octet-stream, Size: 1512 bytes --]
memory: fix XSA-158 fix
For one the uses of domu_max_order and ptdom_max_order were swapped.
And then gcc warns about an unused result of a __must_check function
in the control part of a conditional expression when both other
expressions can be determined by the compiler to produce the same value
(see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68039), which happens
when HAS_PASSTHROUGH is undefined (i.e. for ARM on 4.4 and older).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -55,8 +55,6 @@ 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)
{
@@ -75,8 +73,12 @@ 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;
+ unsigned int order = domu_max_order;
+
+#ifdef HAS_PASSTHROUGH
+ if ( cache_flush_permitted(d) && order < ptdom_max_order )
+ order = ptdom_max_order;
+#endif
if ( is_control_domain(d) && order < ctldom_max_order )
order = ctldom_max_order;
[-- Attachment #5: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-12-10 13:55 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-08 12:01 Xen Security Advisory 158 (CVE-2015-8338) - long running memory operations on ARM Xen.org security team
-- strict thread matches above, loose matches on Subject: below --
2015-12-10 13:55 Xen.org security team
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.