Xen Security Advisory 157 (CVE-2015-8551, CVE-2015-8552) - Linux pciback missing sanity checks leading to crash
Xen.org security team <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.announce |
|---|---|
| Message-ID | <E1a9Xst-0001w5-Ru__37236.9403871291$1450356593$gmane$org@xenbits.xen.org> |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen Security Advisory CVE-2015-8551,CVE-2015-8552 / XSA-157
version 3
Linux pciback missing sanity checks leading to crash
UPDATES IN VERSION 3
====================
Removed CVE-2015-8553 from the title of this advisory. We will issue
an update to XSA-120 which documents the assignment of CVE-2015-8553
to the XSA-120 v5+ addendum patch.
Public release.
ISSUE DESCRIPTION
=================
Xen PCI backend driver does not perform proper sanity checks on the
device's state.
Which in turn allows the generic MSI code (called by Xen PCI backend) to be
called incorrectly leading to hitting BUG conditions or causing NULL pointer
exceptions in the MSI code. (CVE-2015-8551)
To exploit this the guest can craft specific sequence of XEN_PCI_OP_*
operations which will trigger this.
Furthermore the frontend can also craft an continous stream of
XEN_PCI_OP_enable_msi which will trigger an continous
stream of WARN() messages triggered by the MSI code leading to the logging
in the initial domain to exhaust disk space. (CVE-2015-8552)
Lastly there is also missing check to verify whether the device has
memory decoding enabled set at the start of the day leading the initial
domain "accesses to the respective MMIO or I/O port ranges would - - on PCI
Express devices - [which can] lead to Unsupported Request responses.
The treatment of such errors is platform specific." (from XSA-120).
Note that if XSA-120 'addendum' patch (re CVE-2015-8553) has been
applied this particular sub-issue is not exploitable.
IMPACT
======
Malicious guest administrators can cause denial of service. If driver
domains are not in use, the impact is a host crash.
Only x86 systems are vulnerable. ARM systems are not vulnerable.
VULNERABLE SYSTEMS
==================
This bug affects systems using Linux as the driver domain, including
non-disaggregated systems using Linux as dom0.
Linux versions v3.1 and onwards are vulnerable due to supporting PCI
pass-through backend driver.
PV and 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-capable or MSI-X. (Most modern devices
are).
MITIGATION
==========
Not using PCI passthrough for PV and HVM guests. Note that for HVM guests
QEMU is used for PCI passthrough - however the toolstack sets up also
the 'PV' PCI which the guest can utilize if it chooses to do so.
CREDITS
=======
This issue was discovered by Konrad Rzeszutek Wilk of Oracle.
RESOLUTION
==========
Applying the appropriate attached patch resolves this issue.
Linux 4.3:
xsa157-0001-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msi-wh.patch
xsa157-0002-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msix-w.patch
xsa157-0003-xen-pciback-Do-not-install-an-IRQ-handler-for-MSI-in.patch
xsa157-0004-xen-pciback-For-XEN_PCI_OP_disable_msi-x-only-disabl.patch
xsa157-0005-xen-pciback-Don-t-allow-MSI-X-ops-if-PCI_COMMAND_MEM.patch
$ sha256sum xsa157*
0cb2d1729f17e640e33f11945f2e12eba85071238fab2dcc42f81b5d942c159b xsa157-0001-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msi-wh.patch
9bcb240a49a5cd48428cc9c01ee480297999b93f6977fdddd79ec715648aa244 xsa157-0002-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msix-w.patch
7c39b33d0e2d751970bbe56f463661c50aa5e4addc8eee35b80e9e1378e97b02 xsa157-0003-xen-pciback-Do-not-install-an-IRQ-handler-for-MSI-in.patch
1acfd6f4ea13db6a146d547640f50d0ad40480b914b021760a518ac82e8e4c71 xsa157-0004-xen-pciback-For-XEN_PCI_OP_disable_msi-x-only-disabl.patch
b864620709e4b55a908dd6955a090ca03a9a07cfb31b66e2e5211ab8f0c77e68 xsa157-0005-xen-pciback-Don-t-allow-MSI-X-ops-if-PCI_COMMAND_MEM.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)
iQEcBAEBAgAGBQJWcqy7AAoJEIP+FMlX6CvZr/gH+gKO6HcnCeZGPthmt7tKiHxn
oa/VjgDMxIGVHerP0HRXTbletj7XOWhdDNrHNa7JQQXkjXiE+zmLRTVum/ghIxKO
OMSiRtLFm6pkWmOXJI5kvOLDxt1aEECLG0lU9okbk7YmhZE65L4ysIsOGydfzAIn
niKsCnMCxv2MDz5WtFy4okwE+dYJA/MrPfJ1kdJK2y26elxNv895HmwUG8vG042e
NKsqBXWqF8Li2GgrtuXCmUAjHeEFXkouCCh7XVSZo70Zr1kVtFpifeNyz2V72qqh
XRDmYkY5TJy+CD8tSIb82CcPU1JA7X5hFm1AuzYHeYT3+hxG0glcELGde+655Ig=
=i8jn
-----END PGP SIGNATURE-----
_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
xsa157-0001-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msi-wh.patch
(application/octet-stream, 2 KB)
From e3de4a44cfe196e162ddeffd6379e5c4e75ff1d7 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <[email protected]> Date: Fri, 3 Apr 2015 11:08:22 -0400 Subject: [PATCH v2 XSA157 1/5] xen/pciback: Return error on XEN_PCI_OP_enable_msi when device has MSI or MSI-X enabled The guest sequence of: a) XEN_PCI_OP_enable_msi b) XEN_PCI_OP_enable_msi c) XEN_PCI_OP_disable_msi results in hitting an BUG_ON condition in the msi.c code. The MSI code uses an dev->msi_list to which it adds MSI entries. Under the above conditions an BUG_ON() can be hit. The device passed in the guest MUST have MSI capability. The a) adds the entry to the dev->msi_list and sets msi_enabled. The b) adds a second entry but adding in to SysFS fails (duplicate entry) and deletes all of the entries from msi_list and returns (with msi_enabled is still set). c) pci_disable_msi passes the msi_enabled checks and hits: BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); and blows up. The patch adds a simple check in the XEN_PCI_OP_enable_msi to guard against that. The check for msix_enabled is not stricly neccessary. This is part of XSA-157. CC: [email protected] Reviewed-by: David Vrabel <[email protected]> Reviewed-by: Jan Beulich <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> --- drivers/xen/xen-pciback/pciback_ops.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index c4a0666..5ce573a 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -144,7 +144,12 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev, if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: enable MSI\n", pci_name(dev)); - status = pci_enable_msi(dev); + if (dev->msi_enabled) + status = -EALREADY; + else if (dev->msix_enabled) + status = -ENXIO; + else + status = pci_enable_msi(dev); if (status) { pr_warn_ratelimited("%s: error enabling MSI for guest %u: err %d\n", -- 2.1.0
xsa157-0002-xen-pciback-Return-error-on-XEN_PCI_OP_enable_msix-w.patch
(application/octet-stream, 2.2 KB)
From 19b33b70d423ddfea1daf7615eb7f605371a1841 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <[email protected]> Date: Mon, 2 Nov 2015 18:07:44 -0500 Subject: [PATCH v2 XSA157 2/5] xen/pciback: Return error on XEN_PCI_OP_enable_msix when device has MSI or MSI-X enabled The guest sequence of: a) XEN_PCI_OP_enable_msix b) XEN_PCI_OP_enable_msix results in hitting an NULL pointer due to using freed pointers. The device passed in the guest MUST have MSI-X capability. The a) constructs and SysFS representation of MSI and MSI groups. The b) adds a second set of them but adding in to SysFS fails (duplicate entry). 'populate_msi_sysfs' frees the newly allocated msi_irq_groups (note that in a) pdev->msi_irq_groups is still set) and also free's ALL of the MSI-X entries of the device (the ones allocated in step a) and b)). The unwind code: 'free_msi_irqs' deletes all the entries and tries to delete the pdev->msi_irq_groups (which hasn't been set to NULL). However the pointers in the SysFS are already freed and we hit an NULL pointer further on when 'strlen' is attempted on a freed pointer. The patch adds a simple check in the XEN_PCI_OP_enable_msix to guard against that. The check for msi_enabled is not stricly neccessary. This is part of XSA-157 CC: [email protected] Reviewed-by: David Vrabel <[email protected]> Reviewed-by: Jan Beulich <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> --- drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 5ce573a..a107928 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -206,9 +206,16 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n", pci_name(dev)); + if (op->value > SH_INFO_MAX_VEC) return -EINVAL; + if (dev->msix_enabled) + return -EALREADY; + + if (dev->msi_enabled) + return -ENXIO; + entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); if (entries == NULL) return -ENOMEM; -- 2.1.0
xsa157-0003-xen-pciback-Do-not-install-an-IRQ-handler-for-MSI-in.patch
(application/octet-stream, 3 KB)
From aa48314c60da1035a8e6cc05bec12838a074de98 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <[email protected]> Date: Mon, 2 Nov 2015 17:24:08 -0500 Subject: [PATCH v2 XSA157 3/5] xen/pciback: Do not install an IRQ handler for MSI interrupts. Otherwise an guest can subvert the generic MSI code to trigger an BUG_ON condition during MSI interrupt freeing: for (i = 0; i < entry->nvec_used; i++) BUG_ON(irq_has_action(entry->irq + i)); Xen PCI backed installs an IRQ handler (request_irq) for the dev->irq whenever the guest writes PCI_COMMAND_MEMORY (or PCI_COMMAND_IO) to the PCI_COMMAND register. This is done in case the device has legacy interrupts the GSI line is shared by the backend devices. To subvert the backend the guest needs to make the backend to change the dev->irq from the GSI to the MSI interrupt line, make the backend allocate an interrupt handler, and then command the backend to free the MSI interrupt and hit the BUG_ON. Since the backend only calls 'request_irq' when the guest writes to the PCI_COMMAND register the guest needs to call XEN_PCI_OP_enable_msi before any other operation. This will cause the generic MSI code to setup an MSI entry and populate dev->irq with the new PIRQ value. Then the guest can write to PCI_COMMAND PCI_COMMAND_MEMORY and cause the backend to setup an IRQ handler for dev->irq (which instead of the GSI value has the MSI pirq). See 'xen_pcibk_control_isr'. Then the guest disables the MSI: XEN_PCI_OP_disable_msi which ends up triggering the BUG_ON condition in 'free_msi_irqs' as there is an IRQ handler for the entry->irq (dev->irq). Note that this cannot be done using MSI-X as the generic code does not over-write dev->irq with the MSI-X PIRQ values. The patch inhibits setting up the IRQ handler if MSI or MSI-X (for symmetry reasons) code had been called successfully. P.S. Xen PCIBack when it sets up the device for the guest consumption ends up writting 0 to the PCI_COMMAND (see xen_pcibk_reset_device). XSA-120 addendum patch removed that - however when upstreaming said addendum we found that it caused issues with qemu upstream. That has now been fixed in qemu upstream. This is part of XSA-157 CC: [email protected] Reviewed-by: David Vrabel <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> --- drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index a107928..5bb76c0 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -70,6 +70,13 @@ static void xen_pcibk_control_isr(struct pci_dev *dev, int reset) enable ? "enable" : "disable"); if (enable) { + /* + * The MSI or MSI-X should not have an IRQ handler. Otherwise + * if the guest terminates we BUG_ON in free_msi_irqs. + */ + if (dev->msi_enabled || dev->msix_enabled) + goto out; + rc = request_irq(dev_data->irq, xen_pcibk_guest_interrupt, IRQF_SHARED, dev_data->irq_name, dev); -- 2.1.0
xsa157-0004-xen-pciback-For-XEN_PCI_OP_disable_msi-x-only-disabl.patch
(application/octet-stream, 3.2 KB)
From 59a403750d3796b45376041a4843fcde436ae37e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <[email protected]> Date: Wed, 1 Apr 2015 10:49:47 -0400 Subject: [PATCH v2 XSA157 4/5] xen/pciback: For XEN_PCI_OP_disable_msi[|x] only disable if device has MSI(X) enabled. Otherwise just continue on, returning the same values as previously (return of 0, and op->result has the PIRQ value). This does not change the behavior of XEN_PCI_OP_disable_msi[|x]. The pci_disable_msi or pci_disable_msix have the checks for msi_enabled or msix_enabled so they will error out immediately. However the guest can still call these operations and cause us to disable the 'ack_intr'. That means the backend IRQ handler for the legacy interrupt will not respond to interrupts anymore. This will lead to (if the device is causing an interrupt storm) for the Linux generic code to disable the interrupt line. Naturally this will only happen if the device in question is plugged in on the motherboard on shared level interrupt GSI. This is part of XSA-157 CC: [email protected] Reviewed-by: David Vrabel <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> --- drivers/xen/xen-pciback/pciback_ops.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 5bb76c0..648c09c 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -185,20 +185,23 @@ static int xen_pcibk_disable_msi(struct xen_pcibk_device *pdev, struct pci_dev *dev, struct xen_pci_op *op) { - struct xen_pcibk_dev_data *dev_data; - if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: disable MSI\n", pci_name(dev)); - pci_disable_msi(dev); + if (dev->msi_enabled) { + struct xen_pcibk_dev_data *dev_data; + + pci_disable_msi(dev); + + dev_data = pci_get_drvdata(dev); + if (dev_data) + dev_data->ack_intr = 1; + } op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: MSI: %d\n", pci_name(dev), op->value); - dev_data = pci_get_drvdata(dev); - if (dev_data) - dev_data->ack_intr = 1; return 0; } @@ -264,23 +267,27 @@ static int xen_pcibk_disable_msix(struct xen_pcibk_device *pdev, struct pci_dev *dev, struct xen_pci_op *op) { - struct xen_pcibk_dev_data *dev_data; if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: disable MSI-X\n", pci_name(dev)); - pci_disable_msix(dev); + if (dev->msix_enabled) { + struct xen_pcibk_dev_data *dev_data; + + pci_disable_msix(dev); + + dev_data = pci_get_drvdata(dev); + if (dev_data) + dev_data->ack_intr = 1; + } /* * SR-IOV devices (which don't have any legacy IRQ) have * an undefined IRQ value of zero. */ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; if (unlikely(verbose_request)) - printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", pci_name(dev), - op->value); - dev_data = pci_get_drvdata(dev); - if (dev_data) - dev_data->ack_intr = 1; + printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", + pci_name(dev), op->value); return 0; } #endif -- 2.1.0
xsa157-0005-xen-pciback-Don-t-allow-MSI-X-ops-if-PCI_COMMAND_MEM.patch
(application/octet-stream, 2.2 KB)
From e9ab9e04ed76ef06b4ba9a30b3724ca563fdf1fa Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <[email protected]> Date: Mon, 2 Nov 2015 18:13:27 -0500 Subject: [PATCH v2 XSA157 5/5] xen/pciback: Don't allow MSI-X ops if PCI_COMMAND_MEMORY is not set. commit f598282f51 ("PCI: Fix the NIU MSI-X problem in a better way") teaches us that dealing with MSI-X can be troublesome. Further checks in the MSI-X architecture shows that if the PCI_COMMAND_MEMORY bit is turned of in the PCI_COMMAND we may not be able to access the BAR (since they are memory regions). Since the MSI-X tables are located in there.. that can lead to us causing PCIe errors. Inhibit us performing any operation on the MSI-X unless the MEMORY bit is set. Note that Xen hypervisor with: "x86/MSI-X: access MSI-X table only after having enabled MSI-X" will return: xen_pciback: 0000:0a:00.1: error -6 enabling MSI-X for guest 3! When the generic MSI code tries to setup the PIRQ without MEMORY bit set. Which means with later versions of Xen (4.6) this patch is not neccessary. This is part of XSA-157 CC: [email protected] Reviewed-by: Jan Beulich <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> --- drivers/xen/xen-pciback/pciback_ops.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 648c09c..edb9357 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -212,6 +212,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, struct xen_pcibk_dev_data *dev_data; int i, result; struct msix_entry *entries; + u16 cmd; if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n", @@ -223,7 +224,12 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, if (dev->msix_enabled) return -EALREADY; - if (dev->msi_enabled) + /* + * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able + * to access the BARs where the MSI-X entries reside. + */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY)) return -ENXIO; entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); -- 2.1.0