gnttab: fix unmap pin accounting race

Once all {writable} mappings of a grant entry have been unmapped, the
hypervisor informs the guest that the grant entry has been released by
clearing the _GTF_{reading,writing} usage flags in the guest's grant
table as appropriate.

Unfortunately, at the moment, the code that updates the accounting
happens in a different critical section than the one which updates the
usage flags; this means that under the right circumstances, there may be
a window in time after the hypervisor reported the grant as being free
during which the grant referee still had access to the page.

Move the grant accounting code into the same critical section as the
reporting code to make sure this kind of race can't happen.

This is part of XSA-218.

Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Jan Beulich committed 2017-06-20 14:32:03 +02:00
1 parent fae7d5be8b
commit 9a0bd460cf
1 file changed
+17 -15
+17 -15
View File
@@ -1150,15 +1150,8 @@ __gnttab_unmap_common(
PIN_FAIL(act_release_out, GNTST_general_error,
"Bad frame number doesn't match gntref. (%lx != %lx)\n",
op->frame, act->frame);
if ( op->flags & GNTMAP_device_map )
{
ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
op->map->flags &= ~GNTMAP_device_map;
if ( op->flags & GNTMAP_readonly )
act->pin -= GNTPIN_devr_inc;
else
act->pin -= GNTPIN_devw_inc;
}
op->map->flags &= ~GNTMAP_device_map;
}
if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
@@ -1168,12 +1161,7 @@ __gnttab_unmap_common(
op->flags)) < 0 )
goto act_release_out;
ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
op->map->flags &= ~GNTMAP_host_map;
if ( op->flags & GNTMAP_readonly )
act->pin -= GNTPIN_hstr_inc;
else
act->pin -= GNTPIN_hstw_inc;
}
act_release_out:
@@ -1266,6 +1254,12 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
else
put_page_and_type(pg);
}
ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
if ( op->flags & GNTMAP_readonly )
act->pin -= GNTPIN_devr_inc;
else
act->pin -= GNTPIN_devw_inc;
}
if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
@@ -1274,7 +1268,9 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
{
/*
* Suggests that __gntab_unmap_common failed in
* replace_grant_host_mapping() so nothing further to do
* replace_grant_host_mapping() or IOMMU handling, so nothing
* further to do (short of re-establishing the mapping in the
* latter case).
*/
goto act_release_out;
}
@@ -1285,6 +1281,12 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
put_page_type(pg);
put_page(pg);
}
ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
if ( op->flags & GNTMAP_readonly )
act->pin -= GNTPIN_hstr_inc;
else
act->pin -= GNTPIN_hstw_inc;
}
if ( (op->map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.