summaryrefslogtreecommitdiff
path: root/system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch')
-rw-r--r--system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch231
1 files changed, 0 insertions, 231 deletions
diff --git a/system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch b/system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch
deleted file mode 100644
index b07c978b3c..0000000000
--- a/system/xen/xsa/xsa218-0002-gnttab-Avoid-potential-double-put-of-maptrack-entry.patch
+++ /dev/null
@@ -1,231 +0,0 @@
-From bb6d476b09e635baf5e9fb22540ab7c3530d1d98 Mon Sep 17 00:00:00 2001
-From: George Dunlap <george.dunlap@citrix.com>
-Date: Thu, 15 Jun 2017 12:05:14 +0100
-Subject: [PATCH 2/3] gnttab: Avoid potential double-put of maptrack entry
-
-Each grant mapping for a particular domain is tracked by an in-Xen
-"maptrack" entry. This entry is is referenced by a "handle", which is
-given to the guest when it calls gnttab_map_grant_ref().
-
-There are two types of mapping a particular handle can refer to:
-GNTMAP_host_map and GNTMAP_device_map. A given
-gnttab_unmap_grant_ref() call can remove either only one or both of
-these entries. When a particular handle has no entries left, it must
-be freed.
-
-gnttab_unmap_grant_ref() loops through its grant unmap request list
-twice. It first removes entries from any host pagetables and (if
-appropraite) iommus; then it does a single domain TLB flush; then it
-does the clean-up, including telling the granter that entries are no
-longer being used (if appropriate).
-
-At the moment, it's during the first pass that the maptrack flags are
-cleared, but the second pass that the maptrack entry is freed.
-
-Unfortunately this allows the following race, which results in a
-double-free:
-
- A: (pass 1) clear host_map
- B: (pass 1) clear device_map
- A: (pass 2) See that maptrack entry has no mappings, free it
- B: (pass 2) See that maptrack entry has no mappings, free it #
-
-Unfortunately, unlike the active entry pinning update, we can't simply
-move the maptrack flag changes to the second half, because the
-maptrack flags are used to determine if iommu entries need to be
-added: a domain's iommu must never have fewer permissions than the
-maptrack flags indicate, or a subsequent map_grant_ref() might fail to
-add the necessary iommu entries.
-
-Instead, free the maptrack entry in the first pass if there are no
-further mappings.
-
-This is part of XSA-218.
-
-Reported-by: Jan Beulich <jbeulich.com>
-Signed-off-by: George Dunlap <george.dunlap@citrix.com>
-Signed-off-by: Jan Beulich <jbeulich@suse.com>
----
- xen/common/grant_table.c | 77 +++++++++++++++++++++++++++++++++---------------
- 1 file changed, 53 insertions(+), 24 deletions(-)
-
-diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
-index d80bd49..ba10e76 100644
---- a/xen/common/grant_table.c
-+++ b/xen/common/grant_table.c
-@@ -98,8 +98,8 @@ struct gnttab_unmap_common {
- /* Shared state beteen *_unmap and *_unmap_complete */
- u16 flags;
- unsigned long frame;
-- struct grant_mapping *map;
- struct domain *rd;
-+ grant_ref_t ref;
- };
-
- /* Number of unmap operations that are done between each tlb flush */
-@@ -1079,6 +1079,8 @@ __gnttab_unmap_common(
- struct grant_table *lgt, *rgt;
- struct active_grant_entry *act;
- s16 rc = 0;
-+ struct grant_mapping *map;
-+ bool put_handle = false;
-
- ld = current->domain;
- lgt = ld->grant_table;
-@@ -1092,11 +1094,11 @@ __gnttab_unmap_common(
- return;
- }
-
-- op->map = &maptrack_entry(lgt, op->handle);
-+ map = &maptrack_entry(lgt, op->handle);
-
- grant_read_lock(lgt);
-
-- if ( unlikely(!read_atomic(&op->map->flags)) )
-+ if ( unlikely(!read_atomic(&map->flags)) )
- {
- grant_read_unlock(lgt);
- gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
-@@ -1104,7 +1106,7 @@ __gnttab_unmap_common(
- return;
- }
-
-- dom = op->map->domid;
-+ dom = map->domid;
- grant_read_unlock(lgt);
-
- if ( unlikely((rd = rcu_lock_domain_by_id(dom)) == NULL) )
-@@ -1129,16 +1131,43 @@ __gnttab_unmap_common(
-
- grant_read_lock(rgt);
-
-- op->flags = read_atomic(&op->map->flags);
-- if ( unlikely(!op->flags) || unlikely(op->map->domid != dom) )
-+ op->rd = rd;
-+ op->ref = map->ref;
-+
-+ /*
-+ * We can't assume there was no racing unmap for this maptrack entry,
-+ * and hence we can't assume map->ref is valid for rd. While the checks
-+ * below (with the active entry lock held) will reject any such racing
-+ * requests, we still need to make sure we don't attempt to acquire an
-+ * invalid lock.
-+ */
-+ smp_rmb();
-+ if ( unlikely(op->ref >= nr_grant_entries(rgt)) )
- {
- gdprintk(XENLOG_WARNING, "Unstable handle %u\n", op->handle);
- rc = GNTST_bad_handle;
-- goto unmap_out;
-+ goto unlock_out;
- }
-
-- op->rd = rd;
-- act = active_entry_acquire(rgt, op->map->ref);
-+ act = active_entry_acquire(rgt, op->ref);
-+
-+ /*
-+ * Note that we (ab)use the active entry lock here to protect against
-+ * multiple unmaps of the same mapping here. We don't want to hold lgt's
-+ * lock, and we only hold rgt's lock for reading (but the latter wouldn't
-+ * be the right one anyway). Hence the easiest is to rely on a lock we
-+ * hold anyway; see docs/misc/grant-tables.txt's "Locking" section.
-+ */
-+
-+ op->flags = read_atomic(&map->flags);
-+ smp_rmb();
-+ if ( unlikely(!op->flags) || unlikely(map->domid != dom) ||
-+ unlikely(map->ref != op->ref) )
-+ {
-+ gdprintk(XENLOG_WARNING, "Unstable handle %#x\n", op->handle);
-+ rc = GNTST_bad_handle;
-+ goto act_release_out;
-+ }
-
- if ( op->frame == 0 )
- {
-@@ -1151,7 +1180,7 @@ __gnttab_unmap_common(
- "Bad frame number doesn't match gntref. (%lx != %lx)\n",
- op->frame, act->frame);
-
-- op->map->flags &= ~GNTMAP_device_map;
-+ map->flags &= ~GNTMAP_device_map;
- }
-
- if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
-@@ -1161,14 +1190,23 @@ __gnttab_unmap_common(
- op->flags)) < 0 )
- goto act_release_out;
-
-- op->map->flags &= ~GNTMAP_host_map;
-+ map->flags &= ~GNTMAP_host_map;
-+ }
-+
-+ if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
-+ {
-+ map->flags = 0;
-+ put_handle = true;
- }
-
- act_release_out:
- active_entry_release(act);
-- unmap_out:
-+ unlock_out:
- grant_read_unlock(rgt);
-
-+ if ( put_handle )
-+ put_maptrack_handle(lgt, op->handle);
-+
- if ( rc == GNTST_okay && gnttab_need_iommu_mapping(ld) )
- {
- unsigned int kind;
-@@ -1205,7 +1243,6 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
- grant_entry_header_t *sha;
- struct page_info *pg;
- uint16_t *status;
-- bool_t put_handle = 0;
-
- if ( rd == NULL )
- {
-@@ -1226,13 +1263,13 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
- if ( rgt->gt_version == 0 )
- goto unlock_out;
-
-- act = active_entry_acquire(rgt, op->map->ref);
-- sha = shared_entry_header(rgt, op->map->ref);
-+ act = active_entry_acquire(rgt, op->ref);
-+ sha = shared_entry_header(rgt, op->ref);
-
- if ( rgt->gt_version == 1 )
- status = &sha->flags;
- else
-- status = &status_entry(rgt, op->map->ref);
-+ status = &status_entry(rgt, op->ref);
-
- if ( unlikely(op->frame != act->frame) )
- {
-@@ -1289,9 +1326,6 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
- act->pin -= GNTPIN_hstw_inc;
- }
-
-- if ( (op->map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
-- put_handle = 1;
--
- if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
- !(op->flags & GNTMAP_readonly) )
- gnttab_clear_flag(_GTF_writing, status);
-@@ -1304,11 +1338,6 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
- unlock_out:
- grant_read_unlock(rgt);
-
-- if ( put_handle )
-- {
-- op->map->flags = 0;
-- put_maptrack_handle(ld->grant_table, op->handle);
-- }
- rcu_unlock_domain(rd);
- }
-
---
-2.1.4
-