Xen Security Advisory 130 (CVE-2015-4105) - Guest triggerable qemu MSI-X pass-through error messages

Xen.org security team <[email protected]>
Newsgroups gmane.comp.emulators.xen.announce
Message-ID <E1YzmoC-0001pV-KC__28598.1411500417$1433254399$gmane$org@xenbits.xen.org>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

            Xen Security Advisory CVE-2015-4105 / XSA-130
                              version 2

         Guest triggerable qemu MSI-X pass-through error messages

UPDATES IN VERSION 2
====================

Public release.

CVE assigned.

ISSUE DESCRIPTION
=================

Device model code dealing with guest PCI MSI-X interrupt management
activities logs messages on certain (supposedly) invalid guest
operations.

IMPACT
======

A buggy or malicious guest repeatedly invoking such operations may
result in the host disk to fill up, possibly leading to a Denial of
Service.

VULNERABLE SYSTEMS
==================

Xen versions 3.3 and onwards are vulnerable due to supporting PCI
pass-through.

Only x86 systems are vulnerable.  ARM systems are not vulnerable.

Only HVM guests with their device model run in Dom0 can take advantage
of this vulnerability.

Only HVM guests which have been granted access to physical PCI devices
(`PCI passthrough') can take advantage of this vulnerability.

Furthermore, the vulnerability is only applicable when the
passed-through PCI devices are MSI-X capable.  (Many modern devices
are.)

MITIGATION
==========

This issue can be avoided by not assigning MSI-X capable PCI devices to
untrusted HVM guests.

This issue can also be avoided by only using PV guests.

It can also be avoided by configuring HVM guests with their device
model run in a separate (stub) domain.  (When using xl, this can be
requested with "device_model_stubdomain_override=1" in the domain
configuration file.)

CREDITS
=======

This issue was discovered by Jan Beulich of SUSE.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

xsa130-qemuu.patch           qemu-upstream-unstable, Xen 4.5.x, Xen 4.4.x
xsa130-qemuu-4.3.patch       Xen 4.3.x
xsa130-qemut.patch           qemu-xen-unstable, Xen 4.5.x, Xen 4.4.x, Xen 4.3.x, Xen 4.2.x

$ sha256sum xsa130*.patch
0ed6d75b6758c43a3042994f5127cb69d03796acf5c4d305d7ec2486500753da  xsa130-qemut.patch
fd6e835e945c2eee197f9e18501aeefb6e1d33a714f6ce66c16481d5aca8fcd0  xsa130-qemuu-4.3.patch
87fb70041d1fe9c997461c4a6fdaf9157667ec2eff7c77b8db6ee8f9d730753d  xsa130-qemuu.patch
$

DEPLOYMENT DURING EMBARGO
=========================

Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.

But: 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)

iQEcBAEBAgAGBQJVbbdWAAoJEIP+FMlX6CvZhyIH/3VkV4yhOpHsYzHEdkcikqTP
w3KzOsPqtZs2++XWN48Ewpt1Dy12vLkq65hljfvHj9AIWmB0qgWXNC51lkkIFffT
KgcNuUbuJkyy+hNk7K/OWblXbehTrSIAWkl13xKymIQYiS+UN8TYp9kM7QIFkYh2
GGJlCzTljnxeKFZY0z7uW6OKnZzBkdcGmRS5tyH+cqikfAEDSGaV7ffSC0mukd0/
LrTodM+0+8C40znDAyjUiz91YfGXyXtTTEKvmPzdhiv9Fsp3FZ6kMkSGPhcAUUUh
WJmP23QXwm1Tt0qZn9wp1w1DmgihkDoS9Jdw/as29qSCNE2UrfsXaPghGkujQTU=
=KrtH
-----END PGP SIGNATURE-----

_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
xsa130-qemut.patch (application/octet-stream, 545 B)
xen/MSI-X: disable logging by default

... to avoid allowing the guest to cause the control domain's disk to
fill.

This is XSA-130.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>

--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -27,7 +27,7 @@
 #include "qemu-timer.h"
 
 /* Log acesss */
-#define PT_LOGGING_ENABLED
+/* #define PT_LOGGING_ENABLED */
 
 /* Print errors even if logging is disabled */
 #define PT_ERR(_f, _a...)   fprintf(logfile, "%s: " _f, __func__, ##_a)
xsa130-qemuu-4.3.patch (application/octet-stream, 2.8 KB)
xen/MSI-X: limit error messages resulting from bad guest behavior

... to avoid allowing the guest to cause the control domain's disk to
fill.

The first message in pci_msix_write() can simply be deleted, as this
is indeed bad guest behavior, but such out of bounds writes don't
really need to be logged.

The second one is more problematic, as there guest behavior may only
appear to be wrong: For one, the old logic didn't take the mask-all bit
into account. And then this shouldn't depend on host device state (i.e.
the host may have masked the entry without the guest having done so).
Plus these writes shouldn't be dropped even when an entry is unmasked.
Instead, if they can't be made take effect right away, they should take
effect on the next unmasking or enabling operation - the specification
explicitly describes such caching behavior. Until we can validly drop
the message (implementing such caching/latching behavior), issue the
message just once per MSI-X table entry.

Note that the log message in pci_msix_read() similar to the one being
removed here is not an issue: "addr" being of unsigned type, and the
maximum size of the MSI-X table being 32k, entry_nr simply can't be
negative and hence the conditonal guarding issuing of the message will
never be true.

This is XSA-130.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>

--- a/hw/xen_pt.h
+++ b/hw/xen_pt.h
@@ -175,6 +175,7 @@ typedef struct XenPTMSIXEntry {
     uint32_t data;
     uint32_t vector_ctrl;
     bool updated; /* indicate whether MSI ADDR or DATA is updated */
+    bool warned;  /* avoid issuing (bogus) warning more than once */
 } XenPTMSIXEntry;
 typedef struct XenPTMSIX {
     uint32_t ctrl_offset;
--- a/hw/xen_pt_msi.c
+++ b/hw/xen_pt_msi.c
@@ -433,11 +433,10 @@ static void pci_msix_write(void *opaque,
     XenPCIPassthroughState *s = opaque;
     XenPTMSIX *msix = s->msix;
     XenPTMSIXEntry *entry;
-    int entry_nr, offset;
+    unsigned int entry_nr, offset;
 
     entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
-    if (entry_nr < 0 || entry_nr >= msix->total_entries) {
-        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
+    if (entry_nr >= msix->total_entries) {
         return;
     }
     entry = &msix->msix_entry[entry_nr];
@@ -458,8 +457,11 @@ static void pci_msix_write(void *opaque,
             + PCI_MSIX_ENTRY_VECTOR_CTRL;
 
         if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
-                       " already enabled.\n", entry_nr);
+            if (!entry->warned) {
+                entry->warned = true;
+                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
+                           " already enabled.\n", entry_nr);
+            }
             return;
         }
xsa130-qemuu.patch (application/octet-stream, 2.9 KB)
xen/MSI-X: limit error messages resulting from bad guest behavior

... to avoid allowing the guest to cause the control domain's disk to
fill.

The first message in pci_msix_write() can simply be deleted, as this
is indeed bad guest behavior, but such out of bounds writes don't
really need to be logged.

The second one is more problematic, as there guest behavior may only
appear to be wrong: For one, the old logic didn't take the mask-all bit
into account. And then this shouldn't depend on host device state (i.e.
the host may have masked the entry without the guest having done so).
Plus these writes shouldn't be dropped even when an entry is unmasked.
Instead, if they can't be made take effect right away, they should take
effect on the next unmasking or enabling operation - the specification
explicitly describes such caching behavior. Until we can validly drop
the message (implementing such caching/latching behavior), issue the
message just once per MSI-X table entry.

Note that the log message in pci_msix_read() similar to the one being
removed here is not an issue: "addr" being of unsigned type, and the
maximum size of the MSI-X table being 32k, entry_nr simply can't be
negative and hence the conditonal guarding issuing of the message will
never be true.

This is XSA-130.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>

--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -175,6 +175,7 @@ typedef struct XenPTMSIXEntry {
     uint32_t data;
     uint32_t vector_ctrl;
     bool updated; /* indicate whether MSI ADDR or DATA is updated */
+    bool warned;  /* avoid issuing (bogus) warning more than once */
 } XenPTMSIXEntry;
 typedef struct XenPTMSIX {
     uint32_t ctrl_offset;
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -434,11 +434,10 @@ static void pci_msix_write(void *opaque,
     XenPCIPassthroughState *s = opaque;
     XenPTMSIX *msix = s->msix;
     XenPTMSIXEntry *entry;
-    int entry_nr, offset;
+    unsigned int entry_nr, offset;
 
     entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
-    if (entry_nr < 0 || entry_nr >= msix->total_entries) {
-        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
+    if (entry_nr >= msix->total_entries) {
         return;
     }
     entry = &msix->msix_entry[entry_nr];
@@ -460,8 +459,11 @@ static void pci_msix_write(void *opaque,
             + PCI_MSIX_ENTRY_VECTOR_CTRL;
 
         if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
-                       " already enabled.\n", entry_nr);
+            if (!entry->warned) {
+                entry->warned = true;
+                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
+                           " already enabled.\n", entry_nr);
+            }
             return;
         }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.