]> xenbits.xensource.com Git - people/dwmw2/xen.git/commitdiff
x86/mm: don't retain page type reference when IOMMU operation fails
authorJan Beulich <jbeulich@suse.com>
Tue, 5 Mar 2019 14:03:43 +0000 (15:03 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 5 Mar 2019 14:03:43 +0000 (15:03 +0100)
The IOMMU update in _get_page_type() happens between recording of the
new reference and validation of the page for its new type (if
necessary). If the IOMMU operation fails, there's no point in actually
carrying out validation. Furthermore, with this resulting in failure
getting indicated to the caller, the recorded type reference also needs
to be dropped again.

Note that in case of failure of alloc_page_type() there's no need to
undo the IOMMU operation: Only special types get handed to the function.
The function, upon failure, clears ->u.inuse.type_info, effectively
converting the page to PGT_none. The IOMMU mapping, however, solely
depends on whether the type is PGT_writable_page.

This is XSA-291.

Reported-by: Igor Druzhinin <igor.druzhinin@citrix.com>
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: fad0de986220c46e70be2f83279961aad7394af0
master date: 2019-03-05 13:52:15 +0100

xen/arch/x86/mm.c

index f657c1fdbf553cb818f2de5c39c5de4c001afeda..e1f13901adc12a0969a4b0f7df668aed965fea58 100644 (file)
@@ -2896,6 +2896,13 @@ static int _get_page_type(struct page_info *page, unsigned long type,
                 iommu_ret = iommu_map_page(d, gfn_x(gfn),
                                            mfn_x(page_to_mfn(page)),
                                            IOMMUF_readable|IOMMUF_writable);
+
+            if ( unlikely(iommu_ret) )
+            {
+                _put_page_type(page, false, NULL);
+                rc = iommu_ret;
+                goto out;
+            }
         }
     }
 
@@ -2910,12 +2917,10 @@ static int _get_page_type(struct page_info *page, unsigned long type,
         rc = alloc_page_type(page, type, preemptible);
     }
 
+ out:
     if ( (x & PGT_partial) && !(nx & PGT_partial) )
         put_page(page);
 
-    if ( !rc )
-        rc = iommu_ret;
-
     return rc;
 }