summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Grall <jgrall@amazon.com>2022-01-25 13:35:08 +0100
committerJan Beulich <jbeulich@suse.com>2022-01-25 13:35:08 +0100
commit965fbc8e801c91938dd7efa831fb9078a78deeb7 (patch)
tree6b9dca045161092db7d6659a9583c7918be52123
parentacdb6744460c6264785c031a37d99b8557c56195 (diff)
xen/grant-table: Only decrement the refcounter when grant is fully unmapped
The grant unmapping hypercall (GNTTABOP_unmap_grant_ref) is not a simple revert of the changes done by the grant mapping hypercall (GNTTABOP_map_grant_ref). Instead, it is possible to partially (or even not) clear some flags. This will leave the grant is mapped until a future call where all the flags would be cleared. XSA-380 introduced a refcounting that is meant to only be dropped when the grant is fully unmapped. Unfortunately, unmap_common() will decrement the refcount for every successful call. A consequence is a domain would be able to underflow the refcount and trigger a BUG(). Looking at the code, it is not clear to me why a domain would want to partially clear some flags in the grant-table. But as this is part of the ABI, it is better to not change the behavior for now. Fix it by checking if the maptrack handle has been released before decrementing the refcounting. This is CVE-2022-23034 / XSA-394. Fixes: 9781b51efde2 ("gnttab: replace mapkind()") Signed-off-by: Julien Grall <jgrall@amazon.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> master commit: 975a8fb45ca186b3476e5656c6ad5dad1122dbfd master date: 2022-01-25 13:25:49 +0100
-rw-r--r--xen/common/grant_table.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 012a74455b..66f8ce7174 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -1488,8 +1488,15 @@ unmap_common(
if ( put_handle )
put_maptrack_handle(lgt, op->handle);
- /* See the respective comment in map_grant_ref(). */
- if ( rc == GNTST_okay && ld != rd && gnttab_need_iommu_mapping(ld) )
+ /*
+ * map_grant_ref() will only increment the refcount (and update the
+ * IOMMU) once per mapping. So we only want to decrement it once the
+ * maptrack handle has been put, alongside the further IOMMU update.
+ *
+ * For the second and third check, see the respective comment in
+ * map_grant_ref().
+ */
+ if ( put_handle && ld != rd && gnttab_need_iommu_mapping(ld) )
{
void **slot;
union maptrack_node node;