]> xenbits.xensource.com Git - xen.git/commit
steal_page: Get rid of bogus struct page states
authorGeorge Dunlap <george.dunlap@citrix.com>
Fri, 18 Jan 2019 15:00:34 +0000 (15:00 +0000)
committerJan Beulich <jbeulich@suse.com>
Tue, 5 Mar 2019 12:48:08 +0000 (13:48 +0100)
commit3d4868a481eebed232eeacba36ea28e5dee5e946
tree3c433afa065d20e5ee84cb7b68581383f6cc9a31
parent1f0b0bb7773d537bcf169e021495d0986d9809fc
steal_page: Get rid of bogus struct page states

The original rules for `struct page` required the following invariants
at all times:

- refcount > 0 implies owner != NULL
- PGC_allocated implies refcount > 0

steal_page, in a misguided attempt to protect against unknown races,
violates both of these rules, thus introducing other races:

- Temporarily, the count_info has the refcount go to 0 while
  PGC_allocated is set

- It explicitly returns the page PGC_allocated set, but owner == NULL
  and page not on the page_list.

The second one meant that page_get_owner_and_reference() could return
NULL even after having successfully grabbed a reference on the page,
leading the caller to leak the reference (since "couldn't get ref" and
"got ref but no owner" look the same).

Furthermore, rather than grabbing a page reference to ensure that the
owner doesn't change under its feet, it appears to rely on holding
d->page_alloc lock to prevent this.

Unfortunately, this is ineffective: page->owner remains non-NULL for
some time after the count has been set to 0; meaning that it would be
entirely possible for the page to be freed and re-allocated to a
different domain between the page_get_owner() check and the count_info
check.

Modify steal_page to instead follow the appropriate access discipline,
taking the page through series of states similar to being freed and
then re-allocated with MEMF_no_owner:

- Grab an extra reference to make sure we don't race with anyone else
  freeing the page

- Drop both references and PGC_allocated atomically, so that (if
successful), anyone else trying to grab a reference will fail

- Attempt to reset Xen's mappings

- Reset the rest of the state.

Then, modify the two callers appropriately:

- Leave count_info alone (it's already been cleared)
- Call free_domheap_page() directly if appropriate
- Call assign_pages() rather than open-coding a partial assign

With all callers to assign_pages() now passing in pages with the
type_info field clear, tighten the respective assertion there.

This is XSA-287.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
xen/arch/x86/mm.c
xen/common/grant_table.c
xen/common/memory.c
xen/common/page_alloc.c