blob: 966c16e043aaebaf2a4266bfb36884f5c15ae7b4 [file] [log] [blame]
Brad Bishop316dfdd2018-06-25 12:45:53 -04001From: Jan Beulich <jbeulich@suse.com>
2Subject: x86/mm: don't wrongly set page ownership
3
4PV domains can obtain mappings of any pages owned by the correct domain,
5including ones that aren't actually assigned as "normal" RAM, but used
6by Xen internally. At the moment such "internal" pages marked as owned
7by a guest include pages used to track logdirty bits, as well as p2m
8pages and the "unpaged pagetable" for HVM guests. Since the PV memory
9management and shadow code conflict in their use of struct page_info
10fields, and since shadow code is being used for log-dirty handling for
11PV domains, pages coming from the shadow pool must, for PV domains, not
12have the domain set as their owner.
13
14While the change could be done conditionally for just the PV case in
15shadow code, do it unconditionally (and for consistency also for HAP),
16just to be on the safe side.
17
18There's one special case though for shadow code: The page table used for
19running a HVM guest in unpaged mode is subject to get_page() (in
20set_shadow_status()) and hence must have its owner set.
21
22This is XSA-248.
23
24Signed-off-by: Jan Beulich <jbeulich@suse.com>
25Reviewed-by: Tim Deegan <tim@xen.org>
26Reviewed-by: George Dunlap <george.dunlap@citrix.com>
27---
28v2: Drop PGC_page_table related pieces.
29
30--- a/xen/arch/x86/mm/hap/hap.c
31+++ b/xen/arch/x86/mm/hap/hap.c
32@@ -286,8 +286,7 @@ static struct page_info *hap_alloc_p2m_p
33 {
34 d->arch.paging.hap.total_pages--;
35 d->arch.paging.hap.p2m_pages++;
36- page_set_owner(pg, d);
37- pg->count_info |= 1;
38+ ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask));
39 }
40 else if ( !d->arch.paging.p2m_alloc_failed )
41 {
42@@ -302,21 +301,23 @@ static struct page_info *hap_alloc_p2m_p
43
44 static void hap_free_p2m_page(struct domain *d, struct page_info *pg)
45 {
46+ struct domain *owner = page_get_owner(pg);
47+
48 /* This is called both from the p2m code (which never holds the
49 * paging lock) and the log-dirty code (which always does). */
50 paging_lock_recursive(d);
51
52- ASSERT(page_get_owner(pg) == d);
53- /* Should have just the one ref we gave it in alloc_p2m_page() */
54- if ( (pg->count_info & PGC_count_mask) != 1 ) {
55- HAP_ERROR("Odd p2m page %p count c=%#lx t=%"PRtype_info"\n",
56- pg, pg->count_info, pg->u.inuse.type_info);
57+ /* Should still have no owner and count zero. */
58+ if ( owner || (pg->count_info & PGC_count_mask) )
59+ {
60+ HAP_ERROR("d%d: Odd p2m page %"PRI_mfn" d=%d c=%lx t=%"PRtype_info"\n",
61+ d->domain_id, mfn_x(page_to_mfn(pg)),
62+ owner ? owner->domain_id : DOMID_INVALID,
63+ pg->count_info, pg->u.inuse.type_info);
64 WARN();
65+ pg->count_info &= ~PGC_count_mask;
66+ page_set_owner(pg, NULL);
67 }
68- pg->count_info &= ~PGC_count_mask;
69- /* Free should not decrement domain's total allocation, since
70- * these pages were allocated without an owner. */
71- page_set_owner(pg, NULL);
72 d->arch.paging.hap.p2m_pages--;
73 d->arch.paging.hap.total_pages++;
74 hap_free(d, page_to_mfn(pg));
75--- a/xen/arch/x86/mm/shadow/common.c
76+++ b/xen/arch/x86/mm/shadow/common.c
77@@ -1503,32 +1503,29 @@ shadow_alloc_p2m_page(struct domain *d)
78 pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0));
79 d->arch.paging.shadow.p2m_pages++;
80 d->arch.paging.shadow.total_pages--;
81+ ASSERT(!page_get_owner(pg) && !(pg->count_info & PGC_count_mask));
82
83 paging_unlock(d);
84
85- /* Unlike shadow pages, mark p2m pages as owned by the domain.
86- * Marking the domain as the owner would normally allow the guest to
87- * create mappings of these pages, but these p2m pages will never be
88- * in the domain's guest-physical address space, and so that is not
89- * believed to be a concern. */
90- page_set_owner(pg, d);
91- pg->count_info |= 1;
92 return pg;
93 }
94
95 static void
96 shadow_free_p2m_page(struct domain *d, struct page_info *pg)
97 {
98- ASSERT(page_get_owner(pg) == d);
99- /* Should have just the one ref we gave it in alloc_p2m_page() */
100- if ( (pg->count_info & PGC_count_mask) != 1 )
101+ struct domain *owner = page_get_owner(pg);
102+
103+ /* Should still have no owner and count zero. */
104+ if ( owner || (pg->count_info & PGC_count_mask) )
105 {
106- SHADOW_ERROR("Odd p2m page count c=%#lx t=%"PRtype_info"\n",
107+ SHADOW_ERROR("d%d: Odd p2m page %"PRI_mfn" d=%d c=%lx t=%"PRtype_info"\n",
108+ d->domain_id, mfn_x(page_to_mfn(pg)),
109+ owner ? owner->domain_id : DOMID_INVALID,
110 pg->count_info, pg->u.inuse.type_info);
111+ pg->count_info &= ~PGC_count_mask;
112+ page_set_owner(pg, NULL);
113 }
114- pg->count_info &= ~PGC_count_mask;
115 pg->u.sh.type = SH_type_p2m_table; /* p2m code reuses type-info */
116- page_set_owner(pg, NULL);
117
118 /* This is called both from the p2m code (which never holds the
119 * paging lock) and the log-dirty code (which always does). */
120@@ -3132,7 +3129,9 @@ int shadow_enable(struct domain *d, u32
121 e = __map_domain_page(pg);
122 write_32bit_pse_identmap(e);
123 unmap_domain_page(e);
124+ pg->count_info = 1;
125 pg->u.inuse.type_info = PGT_l2_page_table | 1 | PGT_validated;
126+ page_set_owner(pg, d);
127 }
128
129 paging_lock(d);
130@@ -3170,7 +3169,11 @@ int shadow_enable(struct domain *d, u32
131 if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) )
132 p2m_teardown(p2m);
133 if ( rv != 0 && pg != NULL )
134+ {
135+ pg->count_info &= ~PGC_count_mask;
136+ page_set_owner(pg, NULL);
137 shadow_free_p2m_page(d, pg);
138+ }
139 domain_unpause(d);
140 return rv;
141 }
142@@ -3279,7 +3282,22 @@ out:
143
144 /* Must be called outside the lock */
145 if ( unpaged_pagetable )
146+ {
147+ if ( page_get_owner(unpaged_pagetable) == d &&
148+ (unpaged_pagetable->count_info & PGC_count_mask) == 1 )
149+ {
150+ unpaged_pagetable->count_info &= ~PGC_count_mask;
151+ page_set_owner(unpaged_pagetable, NULL);
152+ }
153+ /* Complain here in cases where shadow_free_p2m_page() won't. */
154+ else if ( !page_get_owner(unpaged_pagetable) &&
155+ !(unpaged_pagetable->count_info & PGC_count_mask) )
156+ SHADOW_ERROR("d%d: Odd unpaged pt %"PRI_mfn" c=%lx t=%"PRtype_info"\n",
157+ d->domain_id, mfn_x(page_to_mfn(unpaged_pagetable)),
158+ unpaged_pagetable->count_info,
159+ unpaged_pagetable->u.inuse.type_info);
160 shadow_free_p2m_page(d, unpaged_pagetable);
161+ }
162 }
163
164 void shadow_final_teardown(struct domain *d)