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 | <E1YVIqQ-0002vG-E4__32251.1938437403$1425989395$gmane$org@xenbits.xen.org> |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2015-2150 / XSA-120
version 4
Non-maskable interrupts triggerable by guests
UPDATES IN VERSION 4
====================
Public release.
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
treatmeant 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 patch 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-classic.patch linux-2.6.18-xen.hg
$ sha256sum xsa120*.patch
ecd4568d418d6e275f1eebdba4867e7cfdc6a487292db0e9eff0e9e7e2c91826 xsa120-classic.patch
32441fd3930848f7533f74376648fbeb5e35870661e1259860fe10f9a1f67f88 xsa120.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)
iQEcBAEBAgAGBQJU/tzUAAoJEIP+FMlX6CvZcDcIALHGaamMEPKtOANKkWW7cxJz
zWrgU+6cg/slx6wlgTnHB0/9N/zb9VPUZO3j7TS4VNL6z5zu3S1aTelo5w0F5j2N
rbQrmnJ56P7iTGU0UwerueGPUzRAOqw5JNJK/i7Y2nZo/r7Y8IkwZub8nxpeBaPF
YN3gqd7iTmq5IkM0mQNUuSmneLlMVX32dITSatKjaUNaBI54aH8byM+lUjdFyUYv
tKjb6HJD0upo7e5MPmchC1+/1B+Jm7YfAIMJ6Mn168pHMSy9Zn0p0zFeVGCA41u7
L28yDiIVfu1XWcOLWryAQQ4e/rMv1Bpy7Q259SUUj4bUiQDmRdqOdZmaXHlO/Po=
=H+jB
-----END PGP SIGNATURE-----
_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
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.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, },