summaryrefslogtreecommitdiffstats
path: root/main/xen/xsa26-4.2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/xen/xsa26-4.2.patch')
-rw-r--r--main/xen/xsa26-4.2.patch105
1 files changed, 105 insertions, 0 deletions
diff --git a/main/xen/xsa26-4.2.patch b/main/xen/xsa26-4.2.patch
new file mode 100644
index 000000000..44b8f344e
--- /dev/null
+++ b/main/xen/xsa26-4.2.patch
@@ -0,0 +1,105 @@
+gnttab: fix releasing of memory upon switches between versions
+
+gnttab_unpopulate_status_frames() incompletely freed the pages
+previously used as status frame in that they did not get removed from
+the domain's xenpage_list, thus causing subsequent list corruption
+when those pages did get allocated again for the same or another purpose.
+
+Similarly, grant_table_create() and gnttab_grow_table() both improperly
+clean up in the event of an error - pages already shared with the guest
+can't be freed by just passing them to free_xenheap_page(). Fix this by
+sharing the pages only after all allocations succeeded.
+
+This is CVE-2012-5510 / XSA-26.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Ian Campbell <ian.campbell@citrix.com>
+
+diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
+index c01ad00..6fb2be9 100644
+--- a/xen/common/grant_table.c
++++ b/xen/common/grant_table.c
+@@ -1173,12 +1173,13 @@ fault:
+ }
+
+ static int
+-gnttab_populate_status_frames(struct domain *d, struct grant_table *gt)
++gnttab_populate_status_frames(struct domain *d, struct grant_table *gt,
++ unsigned int req_nr_frames)
+ {
+ unsigned i;
+ unsigned req_status_frames;
+
+- req_status_frames = grant_to_status_frames(gt->nr_grant_frames);
++ req_status_frames = grant_to_status_frames(req_nr_frames);
+ for ( i = nr_status_frames(gt); i < req_status_frames; i++ )
+ {
+ if ( (gt->status[i] = alloc_xenheap_page()) == NULL )
+@@ -1209,7 +1210,12 @@ gnttab_unpopulate_status_frames(struct domain *d, struct grant_table *gt)
+
+ for ( i = 0; i < nr_status_frames(gt); i++ )
+ {
+- page_set_owner(virt_to_page(gt->status[i]), dom_xen);
++ struct page_info *pg = virt_to_page(gt->status[i]);
++
++ BUG_ON(page_get_owner(pg) != d);
++ if ( test_and_clear_bit(_PGC_allocated, &pg->count_info) )
++ put_page(pg);
++ BUG_ON(pg->count_info & ~PGC_xen_heap);
+ free_xenheap_page(gt->status[i]);
+ gt->status[i] = NULL;
+ }
+@@ -1247,19 +1253,18 @@ gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
+ clear_page(gt->shared_raw[i]);
+ }
+
+- /* Share the new shared frames with the recipient domain */
+- for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
+- gnttab_create_shared_page(d, gt, i);
+-
+- gt->nr_grant_frames = req_nr_frames;
+-
+ /* Status pages - version 2 */
+ if (gt->gt_version > 1)
+ {
+- if ( gnttab_populate_status_frames(d, gt) )
++ if ( gnttab_populate_status_frames(d, gt, req_nr_frames) )
+ goto shared_alloc_failed;
+ }
+
++ /* Share the new shared frames with the recipient domain */
++ for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
++ gnttab_create_shared_page(d, gt, i);
++ gt->nr_grant_frames = req_nr_frames;
++
+ return 1;
+
+ shared_alloc_failed:
+@@ -2157,7 +2162,7 @@ gnttab_set_version(XEN_GUEST_HANDLE(gnttab_set_version_t uop))
+
+ if ( op.version == 2 && gt->gt_version < 2 )
+ {
+- res = gnttab_populate_status_frames(d, gt);
++ res = gnttab_populate_status_frames(d, gt, nr_grant_frames(gt));
+ if ( res < 0)
+ goto out_unlock;
+ }
+@@ -2600,14 +2605,15 @@ grant_table_create(
+ clear_page(t->shared_raw[i]);
+ }
+
+- for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
+- gnttab_create_shared_page(d, t, i);
+-
+ /* Status pages for grant table - for version 2 */
+ t->status = xzalloc_array(grant_status_t *,
+ grant_to_status_frames(max_nr_grant_frames));
+ if ( t->status == NULL )
+ goto no_mem_4;
++
++ for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
++ gnttab_create_shared_page(d, t, i);
++
+ t->nr_status_frames = 0;
+
+ /* Okay, install the structure. */