Xen Security Advisory 120 (CVE-2015-2150) - Non-maskable interrupts triggerable by guests

Xen.org security team <[email protected]>
Newsgroups gmane.comp.emulators.xen.announce
Message-ID <E1YcynL-0007ma-7c__13634.9911605523$1427819065$gmane$org@xenbits.xen.org>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

            Xen Security Advisory CVE-2015-2150 / XSA-120
                              version 5

              Non-maskable interrupts triggerable by guests

UPDATES IN VERSION 5
====================

The original patches were incomplete: although they eliminated the
possibility that the guest might disable memory and I/O decoding, they
did not ensure that these bits were set at start of day.  The result
was that a malicious guest could simply avoid enabling them and
continue to exploit the vulnerability.

Well behaved guests would normally enable decoding and therefore would
not normally suffer a regression.

Additional patches are now supplied to resolve this issue.

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

Guests are currently permitted to modify all of the (writable) bits in
the PCI command register of devices passed through to them. This in
particular allows them to disable memory and I/O decoding on the
device unless the device is an SR-IOV virtual function, in which case
subsequent accesses to the respective MMIO or I/O port ranges would
- - on PCI Express devices - lead to Unsupported Request responses. The
treatment of such errors is platform specific.

IMPACT
======

In the event that the platform surfaces aforementioned UR responses as
Non-Maskable Interrupts, and either the OS is configured to treat NMIs
as fatal or (e.g. via ACPI's APEI) the platform tells the OS to treat
these errors as fatal, the host would crash, leading to a Denial of
Service.

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

Xen versions 3.3 and onwards are vulnerable due to supporting PCI
pass-through. Upstream Linux versions 3.1 and onwards are vulnerable
due to supporting PCI backend functionality. Other Linux versions as
well as other OS versions may be vulnerable too.

Any domain which is given access to a non-SR-IOV virtual function PCI
Express device can take advantage of this vulnerability.

MITIGATION
==========

This issue can be avoided by not assigning PCI Express devices other
than SR-IOV virtual functions to untrusted guests.

CREDITS
=======

This issue was discovered by Jan Beulich of SUSE.

RESOLUTION
==========

Applying the appropriate attached patches resolves this issue for the
indicated versions of Linux, but only for ordinary PCI config space
accesses by the guest. See XSA-124 for all other cases.

xsa120.patch                  Linux 3.19
xsa120-addendum.patch         Linux 3.19
xsa120-classic.patch          linux-2.6.18-xen.hg
xsa120-classic-addendum.patch linux-2.6.18-xen.hg

$ sha256sum xsa120*.patch
32441fd3930848f7533f74376648fbeb5e35870661e1259860fe10f9a1f67f88  xsa120.patch
32be0b76f5585e9258ebaed348b40b57014ee5163c313a0523fd46f55ac05210  xsa120-addendum.patch
ecd4568d418d6e275f1eebdba4867e7cfdc6a487292db0e9eff0e9e7e2c91826  xsa120-classic.patch
8b377abe56bebf5030587030bf231c2d5bc1f695e21cc4dfbbd348e9b616849c  xsa120-classic-addendum.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)

iQEcBAEBAgAGBQJVGseNAAoJEIP+FMlX6CvZcR4H/RGyM4VV4/1LLFkERmVe6jCq
KhPGTWw72ZMt+iTGLZYOWGu3CTwpG2RSMWwRUNE9dBinUyq5j8GYW+dpAmtBFCT/
muEW3k+cw4BnhOIi6ny3bcCsxnm7SesrpWAmRvwgZRWljZMA0tHhperl1ioovMG0
+jf7ktNU91li7jTm0BSba7FoWIhfSsY5K+hU0/xMrKOUkzdpYzhu8Uzj9exhijHC
5AJ05XDi88ZuZfR7ZPnVvTOaIJaXsVeiM4rfSpp+SsqTyOZW4+ORpd5ecEp93O/N
LNtcHsUjqwm/ezkwM8oHrGQqYWf7Ms4mRuykIE2X/voG/Cf+kvDQE7fOj++3Db0=
=La+E
-----END PGP SIGNATURE-----

_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
xsa120.patch (application/octet-stream, 3.7 KB)
xen-pciback: limit guest control of command register

Otherwise the guest can abuse that control to cause e.g. PCIe
Unsupported Request responses (by disabling memory and/or I/O decoding
and subsequently causing [CPU side] accesses to the respective address
ranges), which (depending on system configuration) may be fatal to the
host.

This is CVE-2015-2150 / XSA-120.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Konrad Rzeszutek Wilk <[email protected]>

--- a/drivers/xen/xen-pciback/conf_space.c
+++ b/drivers/xen/xen-pciback/conf_space.c
@@ -16,7 +16,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static bool permissive;
+bool permissive;
 module_param(permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
--- a/drivers/xen/xen-pciback/conf_space.h
+++ b/drivers/xen/xen-pciback/conf_space.h
@@ -64,6 +64,8 @@ struct config_field_entry {
 	void *data;
 };
 
+extern bool permissive;
+
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
 /* Add fields to a device - the add_fields macro expects to get a pointer to
--- a/drivers/xen/xen-pciback/conf_space_header.c
+++ b/drivers/xen/xen-pciback/conf_space_header.c
@@ -11,6 +11,10 @@
 #include "pciback.h"
 #include "conf_space.h"
 
+struct pci_cmd_info {
+	u16 val;
+};
+
 struct pci_bar_info {
 	u32 val;
 	u32 len_val;
@@ -20,22 +24,36 @@ struct pci_bar_info {
 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
 
-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+/* Bits guests are allowed to control in permissive mode. */
+#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
+			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
+			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
+
+static void *command_init(struct pci_dev *dev, int offset)
 {
-	int i;
-	int ret;
+	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	int err;
 
-	ret = xen_pcibk_read_config_word(dev, offset, value, data);
-	if (!pci_is_enabled(dev))
-		return ret;
-
-	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-		if (dev->resource[i].flags & IORESOURCE_IO)
-			*value |= PCI_COMMAND_IO;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			*value |= PCI_COMMAND_MEMORY;
+	if (!cmd)
+		return ERR_PTR(-ENOMEM);
+
+	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
+	if (err) {
+		kfree(cmd);
+		return ERR_PTR(err);
 	}
 
+	return cmd;
+}
+
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+	int ret = pci_read_config_word(dev, offset, value);
+	const struct pci_cmd_info *cmd = data;
+
+	*value &= PCI_COMMAND_GUEST;
+	*value |= cmd->val & ~PCI_COMMAND_GUEST;
+
 	return ret;
 }
 
@@ -43,6 +61,8 @@ static int command_write(struct pci_dev 
 {
 	struct xen_pcibk_dev_data *dev_data;
 	int err;
+	u16 val;
+	struct pci_cmd_info *cmd = data;
 
 	dev_data = pci_get_drvdata(dev);
 	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
@@ -83,6 +101,18 @@ static int command_write(struct pci_dev 
 		}
 	}
 
+	cmd->val = value;
+
+	if (!permissive && (!dev_data || !dev_data->permissive))
+		return 0;
+
+	/* Only allow the guest to control certain bits. */
+	err = pci_read_config_word(dev, offset, &val);
+	if (err || val == value)
+		return err;
+	value &= PCI_COMMAND_GUEST;
+	value |= val & ~PCI_COMMAND_GUEST;
+
 	return pci_write_config_word(dev, offset, value);
 }
 
@@ -282,6 +312,8 @@ static const struct config_field header_
 	{
 	 .offset    = PCI_COMMAND,
 	 .size      = 2,
+	 .init      = command_init,
+	 .release   = bar_release,
 	 .u.w.read  = command_read,
 	 .u.w.write = command_write,
 	},
xsa120-addendum.patch (application/octet-stream, 1.8 KB)
From 247ab79234631b66283c47029eb895a8e3663e70 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <[email protected]>
Date: Fri, 27 Mar 2015 13:31:11 -0400
Subject: [PATCH 1/2] xen/pciback: Don't disable PCI_COMMAND on PCI device
 reset.

There is no need for this at all. Worst it means that if
the guest tries to write to BARs it could lead (on certain
platforms) to PCI SERR errors.

Please note that with af6fc858a35b90e89ea7a7ee58e66628c55c776b
"xen-pciback: limit guest control of command register"
a guest is still allowed to enable those control bits (safely), but
is not allowed to disable them and that therefore a well behaved
frontend which enables things before using them will still
function correctly.

This is done via an write to the configuration register 0x4 which
triggers on the backend side:
command_write
  \- pci_enable_device
     \- pci_enable_device_flags
        \- do_pci_enable_device
           \- pcibios_enable_device
              \-pci_enable_resourcess
                [which enables the PCI_COMMAND_MEMORY|PCI_COMMAND_IO]

However guests (and drivers) which don't do this could cause
problems, including the security issues which XSA-120 sought
to address.

Reported-by: Jan Beulich <[email protected]>
Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
---
 drivers/xen/xen-pciback/pciback_ops.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
index c4a0666..26e6513 100644
--- a/drivers/xen/xen-pciback/pciback_ops.c
+++ b/drivers/xen/xen-pciback/pciback_ops.c
@@ -119,8 +119,6 @@ void xen_pcibk_reset_device(struct pci_dev *dev)
 		if (pci_is_enabled(dev))
 			pci_disable_device(dev);
 
-		pci_write_config_word(dev, PCI_COMMAND, 0);
-
 		dev->is_busmaster = 0;
 	} else {
 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-- 
2.1.0
xsa120-classic.patch (application/octet-stream, 3.6 KB)
pciback: limit guest control of command register

Otherwise the guest can abuse that control to cause e.g. PCIe
Unsupported Request responses (by disabling memory and/or I/O decoding
and subsequently causing [CPU side] accesses to the respective address
ranges), which (depending on system configuration) may be fatal to the
host.

This is CVE-2015-2150 / XSA-120.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Konrad Rzeszutek Wilk <[email protected]>

--- a/drivers/xen/pciback/conf_space.c
+++ b/drivers/xen/pciback/conf_space.c
@@ -15,7 +15,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static int permissive;
+int permissive;
 module_param(permissive, bool, 0644);
 
 #define DEFINE_PCI_CONFIG(op,size,type) 			\
--- a/drivers/xen/pciback/conf_space.h
+++ b/drivers/xen/pciback/conf_space.h
@@ -64,6 +64,8 @@ struct config_field_entry {
 	void *data;
 };
 
+extern int permissive;
+
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
 /* Add fields to a device - the add_fields macro expects to get a pointer to
--- a/drivers/xen/pciback/conf_space_header.c
+++ b/drivers/xen/pciback/conf_space_header.c
@@ -9,6 +9,10 @@
 #include "pciback.h"
 #include "conf_space.h"
 
+struct pci_cmd_info {
+	u16 val;
+};
+
 struct pci_bar_info {
 	u32 val;
 	u32 len_val;
@@ -18,28 +22,45 @@ struct pci_bar_info {
 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
 
-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+/* Bits guests are allowed to control in permissive mode. */
+#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
+			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
+			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
+
+static void *command_init(struct pci_dev *dev, int offset)
 {
-	int i;
-	int ret;
+	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	int err;
+
+	if (!cmd)
+		return ERR_PTR(-ENOMEM);
 
-	ret = pciback_read_config_word(dev, offset, value, data);
-	if (!dev->is_enabled)
-		return ret;
-
-	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-		if (dev->resource[i].flags & IORESOURCE_IO)
-			*value |= PCI_COMMAND_IO;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			*value |= PCI_COMMAND_MEMORY;
+	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
+	if (err) {
+		kfree(cmd);
+		return ERR_PTR(err);
 	}
 
+	return cmd;
+}
+
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+	int ret = pci_read_config_word(dev, offset, value);
+	const struct pci_cmd_info *cmd = data;
+
+	*value &= PCI_COMMAND_GUEST;
+	*value |= cmd->val & ~PCI_COMMAND_GUEST;
+
 	return ret;
 }
 
 static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 {
 	int err;
+	u16 val;
+	struct pci_cmd_info *cmd = data;
+	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
 
 	if (!dev->is_enabled && is_enable_cmd(value)) {
 		if (unlikely(verbose_request))
@@ -76,6 +97,18 @@ static int command_write(struct pci_dev 
 		}
 	}
 
+	cmd->val = value;
+
+	if (!permissive && (!dev_data || !dev_data->permissive))
+		return 0;
+
+	/* Only allow the guest to control certain bits. */
+	err = pci_read_config_word(dev, offset, &val);
+	if (err || val == value)
+		return err;
+	value &= PCI_COMMAND_GUEST;
+	value |= val & ~PCI_COMMAND_GUEST;
+
 	return pci_write_config_word(dev, offset, value);
 }
 
@@ -275,6 +308,8 @@ static const struct config_field header_
 	{
 	 .offset    = PCI_COMMAND,
 	 .size      = 2,
+	 .init      = command_init,
+	 .release   = bar_release,
 	 .u.w.read  = command_read,
 	 .u.w.write = command_write,
 	},
xsa120-classic-addendum.patch (application/octet-stream, 1.7 KB)
# HG changeset patch
# User Konrad Rzeszutek Wilk <[email protected]>
# Date 1427814949 14400
#      Tue Mar 31 11:15:49 2015 -0400
# Node ID 2d24c59f9a4a079d127339d0c025d3e5b9914c0e
# Parent  afe2ac5137b8c247dea886c732d09791fe44ac91
xen/pciback: Don't disable PCI_COMMAND on PCI device reset.

There is no need for this at all. Worst it means that if
the guest tries to write to BARs it could lead (on certain
platforms) to PCI SERR errors.

Please note that with af6fc858a35b90e89ea7a7ee58e66628c55c776b
"xen-pciback: limit guest control of command register"
a guest is still allowed to enable those control bits (safely), but
is not allowed to disable them and that therefore a well behaved
frontend which enables things before using them will still
function correctly.

This is done via an write to the configuration register 0x4 which
triggers on the backend side:
command_write
  \- pci_enable_device
     \- pci_enable_device_flags
        \- do_pci_enable_device
           \- pcibios_enable_device
              \-pci_enable_resourcess
                [which enables the PCI_COMMAND_MEMORY|PCI_COMMAND_IO]

However guests (and drivers) which don't do this could cause
problems, including the security issues which XSA-120 sought
to address.

Reported-by: Jan Beulich <[email protected]>
Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>

diff -r afe2ac5137b8 -r 2d24c59f9a4a drivers/xen/pciback/pciback_ops.c
--- a/drivers/xen/pciback/pciback_ops.c	Tue Mar 10 14:38:39 2015 +0100
+++ b/drivers/xen/pciback/pciback_ops.c	Tue Mar 31 11:15:49 2015 -0400
@@ -32,8 +32,6 @@
 #endif
 		pci_disable_device(dev);
 
-		pci_write_config_word(dev, PCI_COMMAND, 0);
-
 		dev->is_enabled = 0;
 		dev->is_busmaster = 0;
 	} else {
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.