Xen Security Advisory 449 v2 (CVE-2023-46839) - pci: phantom functions assigned to incorrect contexts

Xen.org security team posted 1 patch 2 months, 3 weeks ago
Failed in applying to current master (apply log)
xen/drivers/passthrough/pci.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
Xen Security Advisory 449 v2 (CVE-2023-46839) - pci: phantom functions assigned to incorrect contexts
Posted by Xen.org security team 2 months, 3 weeks ago
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

            Xen Security Advisory CVE-2023-46839 / XSA-449
                               version 2

         pci: phantom functions assigned to incorrect contexts

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

Public release.

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

PCI devices can make use of a functionality called phantom functions,
that when enabled allows the device to generate requests using the IDs
of functions that are otherwise unpopulated.  This allows a device to
extend the number of outstanding requests.

Such phantom functions need an IOMMU context setup, but failure to
setup the context is not fatal when the device is assigned.  Not
failing device assignment when such failure happens can lead to the
primary device being assigned to a guest, while some of the phantom
functions are assigned to a different domain.

IMPACT
======

Under certain circumstances a malicious guest assigned a PCI device
with phantom functions may be able to access memory from a previous
owner of the device.

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

Systems running all version of Xen are affected.

Only x86 systems are vulnerable.  Arm systems are not vulnerable.

Only systems using PCI passthrough of devices with phantom functions
are affected.

MITIGATION
==========

There is no mitigation (other than not passing through PCI devices
with phantom functions to guests).

CREDITS
=======

This issue was discovered by Roger Pau Monné of XenServer.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball.  Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.

xsa449.patch           xen-unstable - Xen 4.17.x
xsa449-4.16.patch      Xen 4.16.x - Xen 4.15.x

$ sha256sum xsa449*
f77914aae8f917952f66d863d26314875ff96a0d8178f64c94b95825eabbc8a8  xsa449.patch
8f0302c24535ad4c7379469f33afcfdce08ba6db970e0ca1a1bfdd788af6fc6c  xsa449-4.16.patch
$

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

Deployment of the patches described above (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 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 removing/replacing of pass-through devices or their
replacement by emulated devices is a guest visible configuration
change, which may lead to re-discovery of the issue.

Deployment of this mitigation is permitted only AFTER the embargo ends.

AND: 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-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAmW49O0MHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZqVQH/jvY8MptcxkihMhykNkRON6H5aBaY0UQKzbiCVBy
Q0g6FoE59mHIsoIYvPHFFw0BNbxgubWkJRgowRTtwxKay9HWUKo22eKaLpX9I+TX
LUo7KFE02/MRWus6mjGNdaTghC2SzGghqAcwhQcPzuaE1qS31S/iWXTe9u0hITHv
M/zswSWuZK0UaejBy55hd/+L554yZ976coSFGyjqqIuSHvkR6+NFCzTSLp3GHsue
5CI3ouW0fR2aQ/Gu3pXBPgG464rQ9rQptsFW11uZ1Ahw9T4ZYQis9cRNNsM5I+f8
paGiJO2+y9oYoMkKRrkHXVwkhmZJbFzvpq0e4VkgHwZxbIc=
=L484
-----END PGP SIGNATURE-----
From d8b92b21b224126860978e4c604302f3c1e3bf75 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Wed, 13 Dec 2023 15:51:59 +0100
Subject: [PATCH] pci: fail device assignment if phantom functions cannot be
 assigned
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The current behavior is that no error is reported if (some) phantom functions
fail to be assigned during device add or assignment, so the operation succeeds
even if some phantom functions are not correctly setup.

This can lead to devices possibly being successfully assigned to a domU while
some of the device phantom functions are still assigned to dom0.  Even when the
device is assigned domIO before being assigned to a domU phantom functions
might fail to be assigned to domIO, and also fail to be assigned to the domU,
leaving them assigned to dom0.

Since the device can generate requests using the IDs of those phantom
functions, given the scenario above a device in such state would be in control
of a domU, but still capable of generating transactions that use a context ID
targeting dom0 owned memory.

Modify device assign in order to attempt to deassign the device if phantom
functions failed to be assigned.

Note that device addition is not modified in the same way, as in that case the
device is assigned to a trusted domain, and hence partial assign can lead to
device malfunction but not a security issue.

This is XSA-449 / CVE-2023-46839

Fixes: 4e9950dc1bd2 ('IOMMU: add phantom function support')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/drivers/passthrough/pci.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 1439d1ef2b26..47c0eee7bdcc 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1488,11 +1488,10 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 
     pdev->fault.count = 0;
 
-    if ( (rc = iommu_call(hd->platform_ops, assign_device, d, devfn,
-                          pci_to_dev(pdev), flag)) )
-        goto done;
+    rc = iommu_call(hd->platform_ops, assign_device, d, devfn, pci_to_dev(pdev),
+                    flag);
 
-    for ( ; pdev->phantom_stride; rc = 0 )
+    while ( pdev->phantom_stride && !rc )
     {
         devfn += pdev->phantom_stride;
         if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
@@ -1503,8 +1502,24 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 
  done:
     if ( rc )
-        printk(XENLOG_G_WARNING "%pd: assign (%pp) failed (%d)\n",
-               d, &PCI_SBDF(seg, bus, devfn), rc);
+    {
+        printk(XENLOG_G_WARNING "%pd: assign %s(%pp) failed (%d)\n",
+               d, devfn != pdev->devfn ? "phantom function " : "",
+               &PCI_SBDF(seg, bus, devfn), rc);
+
+        if ( devfn != pdev->devfn && deassign_device(d, seg, bus, pdev->devfn) )
+        {
+            /*
+             * Device with phantom functions that failed to both assign and
+             * rollback.  Mark the device as broken and crash the target domain,
+             * as the state of the functions at this point is unknown and Xen
+             * has no way to assert consistent context assignment among them.
+             */
+            pdev->broken = true;
+            if ( !is_hardware_domain(d) && d != dom_io )
+                domain_crash(d);
+        }
+    }
     /* The device is assigned to dom_io so mark it as quarantined */
     else if ( d == dom_io )
         pdev->quarantine = true;
-- 
2.43.0

From ec5e8c15e30385a62b78f27b752a19c879a91ee1 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Wed, 13 Dec 2023 15:51:59 +0100
Subject: [PATCH] pci: fail device assignment if phantom functions cannot be
 assigned
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The current behavior is that no error is reported if (some) phantom functions
fail to be assigned during device add or assignment, so the operation succeeds
even if some phantom functions are not correctly setup.

This can lead to devices possibly being successfully assigned to a domU while
some of the device phantom functions are still assigned to dom0.  Even when the
device is assigned domIO before being assigned to a domU phantom functions
might fail to be assigned to domIO, and also fail to be assigned to the domU,
leaving them assigned to dom0.

Since the device can generate requests using the IDs of those phantom
functions, given the scenario above a device in such state would be in control
of a domU, but still capable of generating transactions that use a context ID
targeting dom0 owned memory.

Modify device assign in order to attempt to deassign the device if phantom
functions failed to be assigned.

Note that device addition is not modified in the same way, as in that case the
device is assigned to a trusted domain, and hence partial assign can lead to
device malfunction but not a security issue.

This is XSA-449 / CVE-2023-46839

Fixes: 4e9950dc1bd2 ('IOMMU: add phantom function support')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/drivers/passthrough/pci.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index a9da7367c29c..6fc27e7ede40 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1448,10 +1448,9 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 
     pdev->fault.count = 0;
 
-    if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag)) )
-        goto done;
+    rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag);
 
-    for ( ; pdev->phantom_stride; rc = 0 )
+    while ( pdev->phantom_stride && !rc )
     {
         devfn += pdev->phantom_stride;
         if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
@@ -1461,8 +1460,22 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 
  done:
     if ( rc )
-        printk(XENLOG_G_WARNING "%pd: assign (%pp) failed (%d)\n",
-               d, &PCI_SBDF3(seg, bus, devfn), rc);
+    {
+        printk(XENLOG_G_WARNING "%pd: assign %s(%pp) failed (%d)\n",
+               d, devfn != pdev->devfn ? "phantom function " : "",
+               &PCI_SBDF3(seg, bus, devfn), rc);
+
+        if ( devfn != pdev->devfn &&
+             deassign_device(d, seg, bus, pdev->devfn) &&
+             !is_hardware_domain(d) && d != dom_io )
+            /*
+             * Device with phantom functions that failed to both assign and
+             * rollback.  Crash the target domain, as the state of the
+             * functions at this point is unknown and Xen has no way to assert
+             * consistent context assignment among them.
+             */
+            domain_crash(d);
+    }
     /* The device is assigned to dom_io so mark it as quarantined */
     else if ( d == dom_io )
         pdev->quarantine = true;
-- 
2.43.0