mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-08-05 13:27:09 +02:00
168 lines
6.0 KiB
Diff
168 lines
6.0 KiB
Diff
From: Jan Beulich <jbeulich@suse.com>
|
|
Subject: gnttab: don't blindly free status pages upon version change
|
|
|
|
There may still be active mappings, which would trigger the respective
|
|
BUG_ON(). Split the loop into one dealing with the page attributes and
|
|
the second (when the first fully passed) freeing the pages. Return an
|
|
error if any pages still have pending references.
|
|
|
|
This is part of XSA-255.
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
|
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
|
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
|
---
|
|
v4: Add gprintk(XENLOG_ERR, ...) to domain_crash() invocations.
|
|
v3: Call guest_physmap_remove_page() from gnttab_map_frame(), making the
|
|
code unconditional at the same time. Re-base over changes to first
|
|
patch.
|
|
v2: Also deal with translated guests.
|
|
|
|
--- a/xen/common/grant_table.c
|
|
+++ b/xen/common/grant_table.c
|
|
@@ -1636,23 +1636,74 @@ status_alloc_failed:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
-static void
|
|
+static int
|
|
gnttab_unpopulate_status_frames(struct domain *d, struct grant_table *gt)
|
|
{
|
|
- int i;
|
|
+ unsigned int i;
|
|
|
|
for ( i = 0; i < nr_status_frames(gt); i++ )
|
|
{
|
|
struct page_info *pg = virt_to_page(gt->status[i]);
|
|
+ gfn_t gfn = gnttab_get_frame_gfn(gt, true, i);
|
|
+
|
|
+ /*
|
|
+ * For translated domains, recovering from failure after partial
|
|
+ * changes were made is more complicated than it seems worth
|
|
+ * implementing at this time. Hence respective error paths below
|
|
+ * crash the domain in such a case.
|
|
+ */
|
|
+ if ( paging_mode_translate(d) )
|
|
+ {
|
|
+ int rc = gfn_eq(gfn, INVALID_GFN)
|
|
+ ? 0
|
|
+ : guest_physmap_remove_page(d, gfn,
|
|
+ _mfn(page_to_mfn(pg)), 0);
|
|
+
|
|
+ if ( rc )
|
|
+ {
|
|
+ gprintk(XENLOG_ERR,
|
|
+ "Could not remove status frame %u (GFN %#lx) from P2M\n",
|
|
+ i, gfn_x(gfn));
|
|
+ domain_crash(d);
|
|
+ return rc;
|
|
+ }
|
|
+ gnttab_set_frame_gfn(gt, true, i, INVALID_GFN);
|
|
+ }
|
|
|
|
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);
|
|
+
|
|
+ if ( pg->count_info & ~PGC_xen_heap )
|
|
+ {
|
|
+ if ( paging_mode_translate(d) )
|
|
+ {
|
|
+ gprintk(XENLOG_ERR,
|
|
+ "Wrong page state %#lx of status frame %u (GFN %#lx)\n",
|
|
+ pg->count_info, i, gfn_x(gfn));
|
|
+ domain_crash(d);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if ( get_page(pg, d) )
|
|
+ set_bit(_PGC_allocated, &pg->count_info);
|
|
+ while ( i-- )
|
|
+ gnttab_create_status_page(d, gt, i);
|
|
+ }
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ page_set_owner(pg, NULL);
|
|
+ }
|
|
+
|
|
+ for ( i = 0; i < nr_status_frames(gt); i++ )
|
|
+ {
|
|
free_xenheap_page(gt->status[i]);
|
|
gt->status[i] = NULL;
|
|
}
|
|
gt->nr_status_frames = 0;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -2962,8 +3013,9 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARA
|
|
break;
|
|
}
|
|
|
|
- if ( op.version < 2 && gt->gt_version == 2 )
|
|
- gnttab_unpopulate_status_frames(currd, gt);
|
|
+ if ( op.version < 2 && gt->gt_version == 2 &&
|
|
+ (res = gnttab_unpopulate_status_frames(currd, gt)) != 0 )
|
|
+ goto out_unlock;
|
|
|
|
/* Make sure there's no crud left over from the old version. */
|
|
for ( i = 0; i < nr_grant_frames(gt); i++ )
|
|
@@ -3803,6 +3855,11 @@ int gnttab_map_frame(struct domain *d, u
|
|
rc = -EINVAL;
|
|
}
|
|
|
|
+ if ( !rc && paging_mode_translate(d) &&
|
|
+ !gfn_eq(gnttab_get_frame_gfn(gt, status, idx), INVALID_GFN) )
|
|
+ rc = guest_physmap_remove_page(d, gnttab_get_frame_gfn(gt, status, idx),
|
|
+ *mfn, 0);
|
|
+
|
|
if ( !rc )
|
|
gnttab_set_frame_gfn(gt, status, idx, gfn);
|
|
|
|
--- a/xen/include/asm-arm/grant_table.h
|
|
+++ b/xen/include/asm-arm/grant_table.h
|
|
@@ -73,6 +73,11 @@ static inline unsigned int gnttab_dom0_m
|
|
(gfn); \
|
|
} while ( 0 )
|
|
|
|
+#define gnttab_get_frame_gfn(gt, st, idx) ({ \
|
|
+ _gfn((st) ? gnttab_status_gmfn(NULL, gt, idx) \
|
|
+ : gnttab_shared_gmfn(NULL, gt, idx)); \
|
|
+})
|
|
+
|
|
#define gnttab_create_shared_page(d, t, i) \
|
|
do { \
|
|
share_xen_page_with_guest( \
|
|
--- a/xen/include/asm-x86/grant_table.h
|
|
+++ b/xen/include/asm-x86/grant_table.h
|
|
@@ -47,6 +47,12 @@ static inline unsigned int gnttab_dom0_m
|
|
#define gnttab_init_arch(gt) 0
|
|
#define gnttab_destroy_arch(gt) do {} while ( 0 )
|
|
#define gnttab_set_frame_gfn(gt, st, idx, gfn) do {} while ( 0 )
|
|
+#define gnttab_get_frame_gfn(gt, st, idx) ({ \
|
|
+ unsigned long mfn_ = (st) ? gnttab_status_mfn(gt, idx) \
|
|
+ : gnttab_shared_mfn(gt, idx); \
|
|
+ unsigned long gpfn_ = get_gpfn_from_mfn(mfn_); \
|
|
+ VALID_M2P(gpfn_) ? _gfn(gpfn_) : INVALID_GFN; \
|
|
+})
|
|
|
|
#define gnttab_create_shared_page(d, t, i) \
|
|
do { \
|
|
@@ -63,11 +69,11 @@ static inline unsigned int gnttab_dom0_m
|
|
} while ( 0 )
|
|
|
|
|
|
-#define gnttab_shared_mfn(d, t, i) \
|
|
+#define gnttab_shared_mfn(t, i) \
|
|
((virt_to_maddr((t)->shared_raw[i]) >> PAGE_SHIFT))
|
|
|
|
#define gnttab_shared_gmfn(d, t, i) \
|
|
- (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i)))
|
|
+ (mfn_to_gmfn(d, gnttab_shared_mfn(t, i)))
|
|
|
|
|
|
#define gnttab_status_mfn(t, i) \
|