aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2013-07-01 14:38:45 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2013-07-01 14:44:49 +0000
commitccdb8c3a1257db6b1ceb3af663b239003a047fd3 (patch)
tree55359f18760f9b250978f861185fd3ac9aa979ba
parent02bb9229c574679953a432211e3a4590ecda8419 (diff)
downloadalpine_aports-ccdb8c3a1257db6b1ceb3af663b239003a047fd3.tar.bz2
alpine_aports-ccdb8c3a1257db6b1ceb3af663b239003a047fd3.tar.xz
alpine_aports-ccdb8c3a1257db6b1ceb3af663b239003a047fd3.zip
main/xen: fix xsa45 and xsa58 (CVE-2013-1918,CVE-2013-1432)
ref #2123 fixes #2124 (cherry picked from commit 448e4822bbf8a2b4aa8b8f8d8153a2a0b4e0efda) Conflicts: main/xen/APKBUILD
-rw-r--r--main/xen/APKBUILD10
-rw-r--r--main/xen/xsa45-4.2.patch1133
-rw-r--r--main/xen/xsa58-4.2.patch129
3 files changed, 1271 insertions, 1 deletions
diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD
index b85ef834d1..29eae12a17 100644
--- a/main/xen/APKBUILD
+++ b/main/xen/APKBUILD
@@ -3,7 +3,7 @@
3# Maintainer: William Pitcock <nenolod@dereferenced.org> 3# Maintainer: William Pitcock <nenolod@dereferenced.org>
4pkgname=xen 4pkgname=xen
5pkgver=4.2.2 5pkgver=4.2.2
6pkgrel=4 6pkgrel=5
7pkgdesc="Xen hypervisor" 7pkgdesc="Xen hypervisor"
8url="http://www.xen.org/" 8url="http://www.xen.org/"
9arch="x86 x86_64" 9arch="x86 x86_64"
@@ -23,6 +23,7 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g
23 xsa41.patch 23 xsa41.patch
24 xsa41b.patch 24 xsa41b.patch
25 xsa41c.patch 25 xsa41c.patch
26 xsa45-4.2.patch
26 xsa48-4.2.patch 27 xsa48-4.2.patch
27 xsa52-4.2-unstable.patch 28 xsa52-4.2-unstable.patch
28 xsa53-4.2.patch 29 xsa53-4.2.patch
@@ -30,6 +31,7 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g
30 xsa55.patch 31 xsa55.patch
31 xsa56.patch 32 xsa56.patch
32 xsa57.patch 33 xsa57.patch
34 xsa58-4.2.patch
33 35
34 fix-pod2man-choking.patch 36 fix-pod2man-choking.patch
35 37
@@ -153,6 +155,7 @@ md5sums="f7362b19401a47826f2d8fd603a1782a xen-4.2.2.tar.gz
1538ad8942000b8a4be4917599cad9209cf xsa41.patch 1558ad8942000b8a4be4917599cad9209cf xsa41.patch
154ed7d0399c6ca6aeee479da5d8f807fe0 xsa41b.patch 156ed7d0399c6ca6aeee479da5d8f807fe0 xsa41b.patch
1552f3dd7bdc59d104370066d6582725575 xsa41c.patch 1572f3dd7bdc59d104370066d6582725575 xsa41c.patch
1589265540493f41f7d40c48d0886ec5823 xsa45-4.2.patch
156b3e3a57d189a4f86c9766eaf3b5207f4 xsa48-4.2.patch 159b3e3a57d189a4f86c9766eaf3b5207f4 xsa48-4.2.patch
15783a9cdd035bcd18bf035434a1ba08c38 xsa52-4.2-unstable.patch 16083a9cdd035bcd18bf035434a1ba08c38 xsa52-4.2-unstable.patch
15803a1a4ebc470ee7e638e04db2701a4f7 xsa53-4.2.patch 16103a1a4ebc470ee7e638e04db2701a4f7 xsa53-4.2.patch
@@ -160,6 +163,7 @@ a8393d1ec6b886ea72ffe624a04ee10a xsa54.patch
16042cd104f2a33d67938a63a6372cff573 xsa55.patch 16342cd104f2a33d67938a63a6372cff573 xsa55.patch
161e70b9128ffc2175cea314a533a7d8457 xsa56.patch 164e70b9128ffc2175cea314a533a7d8457 xsa56.patch
1627475158130474ee062a4eb878259af61 xsa57.patch 1657475158130474ee062a4eb878259af61 xsa57.patch
1667de2cd11c10d6a554f3c81e0688c38b7 xsa58-4.2.patch
163c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch 167c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch
16495d8af17bf844d41a015ff32aae51ba1 xenstored.initd 16895d8af17bf844d41a015ff32aae51ba1 xenstored.initd
165b017ccdd5e1c27bbf1513e3569d4ff07 xenstored.confd 169b017ccdd5e1c27bbf1513e3569d4ff07 xenstored.confd
@@ -180,6 +184,7 @@ a0c225d716d343fe041b63e3940900c5b3573ed3bcfc5b7c2d52ea2861c3fc28 docs-Fix-gener
18093452beba88a8da8e89b8bfa743074a358ba1d9052151c608e21c4d62f8c4867 xsa41.patch 18493452beba88a8da8e89b8bfa743074a358ba1d9052151c608e21c4d62f8c4867 xsa41.patch
181896a07f57310c9bea9bc2a305166cf796282c381cb7839be49105b1726a860b5 xsa41b.patch 185896a07f57310c9bea9bc2a305166cf796282c381cb7839be49105b1726a860b5 xsa41b.patch
182683dd96a0a8899f794070c8c09643dfeeb39f92da531955cba961b45f6075914 xsa41c.patch 186683dd96a0a8899f794070c8c09643dfeeb39f92da531955cba961b45f6075914 xsa41c.patch
187f3c8c75cc6f55409139b1928017d1e432e5e64b6fac2083395f4723353e1c775 xsa45-4.2.patch
183dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patch 188dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patch
1845b8582185bf90386729e81db1f7780c69a891b074a87d9a619a90d6f639bea13 xsa52-4.2-unstable.patch 1895b8582185bf90386729e81db1f7780c69a891b074a87d9a619a90d6f639bea13 xsa52-4.2-unstable.patch
185785f7612bd229f7501f4e98e4760f307d90c64305ee14707d262b77f05fa683d xsa53-4.2.patch 190785f7612bd229f7501f4e98e4760f307d90c64305ee14707d262b77f05fa683d xsa53-4.2.patch
@@ -187,6 +192,7 @@ dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patc
187ac3ebaf3ec37e28ba08e23d63626d7aaccf0a3f282dd0af9c24cc4df3fd8fae0 xsa55.patch 192ac3ebaf3ec37e28ba08e23d63626d7aaccf0a3f282dd0af9c24cc4df3fd8fae0 xsa55.patch
188a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch 193a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch
189b6a5106848541972519cc529859d9ff3083c79367276c7031560fa4ce6f9f770 xsa57.patch 194b6a5106848541972519cc529859d9ff3083c79367276c7031560fa4ce6f9f770 xsa57.patch
195194d6610fc38b767d643e5d58a1268f45921fb35e309b47aca6a388b861311c2 xsa58-4.2.patch
190b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch 196b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch
19181d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd 19781d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd
192ea9171e71ab3d33061979bcf3bb737156192aa4b0be4d1234438ced75b6fdef3 xenstored.confd 198ea9171e71ab3d33061979bcf3bb737156192aa4b0be4d1234438ced75b6fdef3 xenstored.confd
@@ -207,6 +213,7 @@ sha512sums="4943b18016ed8c2b194a3b55e6655b3b734b39ffb8cb7ee0a0580f2f4460a1d0e92e
20794672a4d37db4e370370157cac9507ee1a75832f4be779fba148c1faa0b18f26ed57126eee6256ccd5d218463325a730266b53139554f4865adedb7659154c16 xsa41.patch 21394672a4d37db4e370370157cac9507ee1a75832f4be779fba148c1faa0b18f26ed57126eee6256ccd5d218463325a730266b53139554f4865adedb7659154c16 xsa41.patch
208bda9105793f2327e1317991762120d0668af0e964076b18c9fdbfd509984b2e88d85df95702c46b2e00d5350e8113f6aa7b34b19064d19abbeb4d43f0c431d38 xsa41b.patch 214bda9105793f2327e1317991762120d0668af0e964076b18c9fdbfd509984b2e88d85df95702c46b2e00d5350e8113f6aa7b34b19064d19abbeb4d43f0c431d38 xsa41b.patch
20936b60478660ff7748328f5ab9adff13286eee1a1bad06e42fdf7e6aafe105103988525725aacd660cf5b2a184a9e2d6b3818655203c1fa07e07dcebdf23f35d9 xsa41c.patch 21536b60478660ff7748328f5ab9adff13286eee1a1bad06e42fdf7e6aafe105103988525725aacd660cf5b2a184a9e2d6b3818655203c1fa07e07dcebdf23f35d9 xsa41c.patch
216a57b4c8be76a938d51e51ffb39f0781389ebef320f359b0ae9af4a93af970d37dde50a304d4864a75b7fb32861a4745b9da5fa6acce0f2a688b11b13ab43fb4e xsa45-4.2.patch
21031dd8c62d41cc0a01a79d9b24a5b793f5e2058230808d9c5364c6ff3477ab02f3258f1bbd761d97dc1b97ee120b41524b999eaac77f33b606496fc324b5fa2e4 xsa48-4.2.patch 21731dd8c62d41cc0a01a79d9b24a5b793f5e2058230808d9c5364c6ff3477ab02f3258f1bbd761d97dc1b97ee120b41524b999eaac77f33b606496fc324b5fa2e4 xsa48-4.2.patch
211b64a965fab8534958e453c493211ed3a6555aafb90d18f6d56a45b41d3086a0029aee85b6b6eb93b0d861d5fdc0ef10fc32e9b4f83593b37c43922d838085dd8 xsa52-4.2-unstable.patch 218b64a965fab8534958e453c493211ed3a6555aafb90d18f6d56a45b41d3086a0029aee85b6b6eb93b0d861d5fdc0ef10fc32e9b4f83593b37c43922d838085dd8 xsa52-4.2-unstable.patch
2129b08924e563e79d2b308c1521da520c0579b334b61ac99a5593eabdb96dbda2da898b542cc47bda6d663c68343216d9d29c04853b6d1b6ecdde964b0cbb3f7ab xsa53-4.2.patch 2199b08924e563e79d2b308c1521da520c0579b334b61ac99a5593eabdb96dbda2da898b542cc47bda6d663c68343216d9d29c04853b6d1b6ecdde964b0cbb3f7ab xsa53-4.2.patch
@@ -214,6 +221,7 @@ c9010be637d4f96ef03c880e1ef28228f762c5980108380a105bd190b631a882c8dff81e9421246d
214b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a08797271a3dbc756d3f705a990991c8d2fc96f0f272c3665a xsa55.patch 221b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a08797271a3dbc756d3f705a990991c8d2fc96f0f272c3665a xsa55.patch
21526a1c2cc92ddd4c1ab6712b0e41a0135d0e76a7fe3a14b651fb0235e352e5a24077414371acccb93058b7ce4d882b667386811170ba74570c53165837bcd983d xsa56.patch 22226a1c2cc92ddd4c1ab6712b0e41a0135d0e76a7fe3a14b651fb0235e352e5a24077414371acccb93058b7ce4d882b667386811170ba74570c53165837bcd983d xsa56.patch
2165ccc1654d9f0270485495f9fc913e41663ddbda602ffe049e0a9c3247c6246690b7ec4165482f96921c5253a2a5205ca384048339996e611c07ab60a6a75cf6a xsa57.patch 2235ccc1654d9f0270485495f9fc913e41663ddbda602ffe049e0a9c3247c6246690b7ec4165482f96921c5253a2a5205ca384048339996e611c07ab60a6a75cf6a xsa57.patch
22460813c01f6bb909da8748919df4d0ffa923baf4b7b55287e0bec3389fb83020158225182e112941c9e126b4df57e7b8724f2a69d0c1fa9ce3b37c0bdf1a49da4 xsa58-4.2.patch
217ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch 225ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch
218792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd 226792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd
219100cf4112f401f45c1e4e885a5074698c484b40521262f6268fad286498e95f4c51e746f0e94eb43a590bb8e813a397bb53801ccacebec9541020799d8d70514 xenstored.confd 227100cf4112f401f45c1e4e885a5074698c484b40521262f6268fad286498e95f4c51e746f0e94eb43a590bb8e813a397bb53801ccacebec9541020799d8d70514 xenstored.confd
diff --git a/main/xen/xsa45-4.2.patch b/main/xen/xsa45-4.2.patch
new file mode 100644
index 0000000000..dfdfdea64b
--- /dev/null
+++ b/main/xen/xsa45-4.2.patch
@@ -0,0 +1,1133 @@
1diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
2index 26a7f12..b97ac6d 100644
3--- a/xen/arch/x86/domain.c
4+++ b/xen/arch/x86/domain.c
5@@ -73,8 +73,6 @@ void (*dead_idle) (void) __read_mostly = default_dead_idle;
6 static void paravirt_ctxt_switch_from(struct vcpu *v);
7 static void paravirt_ctxt_switch_to(struct vcpu *v);
8
9-static void vcpu_destroy_pagetables(struct vcpu *v);
10-
11 static void default_idle(void)
12 {
13 local_irq_disable();
14@@ -860,6 +858,9 @@ int arch_set_info_guest(
15
16 if ( !v->is_initialised )
17 {
18+ if ( !compat && !(flags & VGCF_in_kernel) && !c.nat->ctrlreg[1] )
19+ return -EINVAL;
20+
21 v->arch.pv_vcpu.ldt_base = c(ldt_base);
22 v->arch.pv_vcpu.ldt_ents = c(ldt_ents);
23 }
24@@ -957,24 +958,44 @@ int arch_set_info_guest(
25 if ( rc != 0 )
26 return rc;
27
28+ set_bit(_VPF_in_reset, &v->pause_flags);
29+
30 if ( !compat )
31- {
32 cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[3]);
33- cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
34-
35- if ( !cr3_page )
36- {
37- destroy_gdt(v);
38- return -EINVAL;
39- }
40- if ( !paging_mode_refcounts(d)
41- && !get_page_type(cr3_page, PGT_base_page_table) )
42- {
43- put_page(cr3_page);
44- destroy_gdt(v);
45- return -EINVAL;
46- }
47+#ifdef CONFIG_COMPAT
48+ else
49+ cr3_gfn = compat_cr3_to_pfn(c.cmp->ctrlreg[3]);
50+#endif
51+ cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
52
53+ if ( !cr3_page )
54+ rc = -EINVAL;
55+ else if ( paging_mode_refcounts(d) )
56+ /* nothing */;
57+ else if ( cr3_page == v->arch.old_guest_table )
58+ {
59+ v->arch.old_guest_table = NULL;
60+ put_page(cr3_page);
61+ }
62+ else
63+ {
64+ /*
65+ * Since v->arch.guest_table{,_user} are both NULL, this effectively
66+ * is just a call to put_old_guest_table().
67+ */
68+ if ( !compat )
69+ rc = vcpu_destroy_pagetables(v);
70+ if ( !rc )
71+ rc = get_page_type_preemptible(cr3_page,
72+ !compat ? PGT_root_page_table
73+ : PGT_l3_page_table);
74+ if ( rc == -EINTR )
75+ rc = -EAGAIN;
76+ }
77+ if ( rc )
78+ /* handled below */;
79+ else if ( !compat )
80+ {
81 v->arch.guest_table = pagetable_from_page(cr3_page);
82 #ifdef __x86_64__
83 if ( c.nat->ctrlreg[1] )
84@@ -982,56 +1003,44 @@ int arch_set_info_guest(
85 cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[1]);
86 cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
87
88- if ( !cr3_page ||
89- (!paging_mode_refcounts(d)
90- && !get_page_type(cr3_page, PGT_base_page_table)) )
91+ if ( !cr3_page )
92+ rc = -EINVAL;
93+ else if ( !paging_mode_refcounts(d) )
94 {
95- if (cr3_page)
96- put_page(cr3_page);
97- cr3_page = pagetable_get_page(v->arch.guest_table);
98- v->arch.guest_table = pagetable_null();
99- if ( paging_mode_refcounts(d) )
100- put_page(cr3_page);
101- else
102- put_page_and_type(cr3_page);
103- destroy_gdt(v);
104- return -EINVAL;
105+ rc = get_page_type_preemptible(cr3_page, PGT_root_page_table);
106+ switch ( rc )
107+ {
108+ case -EINTR:
109+ rc = -EAGAIN;
110+ case -EAGAIN:
111+ v->arch.old_guest_table =
112+ pagetable_get_page(v->arch.guest_table);
113+ v->arch.guest_table = pagetable_null();
114+ break;
115+ }
116 }
117-
118- v->arch.guest_table_user = pagetable_from_page(cr3_page);
119- }
120- else if ( !(flags & VGCF_in_kernel) )
121- {
122- destroy_gdt(v);
123- return -EINVAL;
124+ if ( !rc )
125+ v->arch.guest_table_user = pagetable_from_page(cr3_page);
126 }
127 }
128 else
129 {
130 l4_pgentry_t *l4tab;
131
132- cr3_gfn = compat_cr3_to_pfn(c.cmp->ctrlreg[3]);
133- cr3_page = get_page_from_gfn(d, cr3_gfn, NULL, P2M_ALLOC);
134-
135- if ( !cr3_page)
136- {
137- destroy_gdt(v);
138- return -EINVAL;
139- }
140-
141- if (!paging_mode_refcounts(d)
142- && !get_page_type(cr3_page, PGT_l3_page_table) )
143- {
144- put_page(cr3_page);
145- destroy_gdt(v);
146- return -EINVAL;
147- }
148-
149 l4tab = __va(pagetable_get_paddr(v->arch.guest_table));
150 *l4tab = l4e_from_pfn(page_to_mfn(cr3_page),
151 _PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED);
152 #endif
153 }
154+ if ( rc )
155+ {
156+ if ( cr3_page )
157+ put_page(cr3_page);
158+ destroy_gdt(v);
159+ return rc;
160+ }
161+
162+ clear_bit(_VPF_in_reset, &v->pause_flags);
163
164 if ( v->vcpu_id == 0 )
165 update_domain_wallclock_time(d);
166@@ -1053,17 +1062,16 @@ int arch_set_info_guest(
167 #undef c
168 }
169
170-void arch_vcpu_reset(struct vcpu *v)
171+int arch_vcpu_reset(struct vcpu *v)
172 {
173 if ( !is_hvm_vcpu(v) )
174 {
175 destroy_gdt(v);
176- vcpu_destroy_pagetables(v);
177- }
178- else
179- {
180- vcpu_end_shutdown_deferral(v);
181+ return vcpu_destroy_pagetables(v);
182 }
183+
184+ vcpu_end_shutdown_deferral(v);
185+ return 0;
186 }
187
188 /*
189@@ -2069,63 +2077,6 @@ static int relinquish_memory(
190 return ret;
191 }
192
193-static void vcpu_destroy_pagetables(struct vcpu *v)
194-{
195- struct domain *d = v->domain;
196- unsigned long pfn;
197-
198-#ifdef __x86_64__
199- if ( is_pv_32on64_vcpu(v) )
200- {
201- pfn = l4e_get_pfn(*(l4_pgentry_t *)
202- __va(pagetable_get_paddr(v->arch.guest_table)));
203-
204- if ( pfn != 0 )
205- {
206- if ( paging_mode_refcounts(d) )
207- put_page(mfn_to_page(pfn));
208- else
209- put_page_and_type(mfn_to_page(pfn));
210- }
211-
212- l4e_write(
213- (l4_pgentry_t *)__va(pagetable_get_paddr(v->arch.guest_table)),
214- l4e_empty());
215-
216- v->arch.cr3 = 0;
217- return;
218- }
219-#endif
220-
221- pfn = pagetable_get_pfn(v->arch.guest_table);
222- if ( pfn != 0 )
223- {
224- if ( paging_mode_refcounts(d) )
225- put_page(mfn_to_page(pfn));
226- else
227- put_page_and_type(mfn_to_page(pfn));
228- v->arch.guest_table = pagetable_null();
229- }
230-
231-#ifdef __x86_64__
232- /* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
233- pfn = pagetable_get_pfn(v->arch.guest_table_user);
234- if ( pfn != 0 )
235- {
236- if ( !is_pv_32bit_vcpu(v) )
237- {
238- if ( paging_mode_refcounts(d) )
239- put_page(mfn_to_page(pfn));
240- else
241- put_page_and_type(mfn_to_page(pfn));
242- }
243- v->arch.guest_table_user = pagetable_null();
244- }
245-#endif
246-
247- v->arch.cr3 = 0;
248-}
249-
250 int domain_relinquish_resources(struct domain *d)
251 {
252 int ret;
253@@ -2143,7 +2094,11 @@ int domain_relinquish_resources(struct domain *d)
254
255 /* Drop the in-use references to page-table bases. */
256 for_each_vcpu ( d, v )
257- vcpu_destroy_pagetables(v);
258+ {
259+ ret = vcpu_destroy_pagetables(v);
260+ if ( ret )
261+ return ret;
262+ }
263
264 if ( !is_hvm_domain(d) )
265 {
266diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
267index 3d471a5..efacc98 100644
268--- a/xen/arch/x86/hvm/hvm.c
269+++ b/xen/arch/x86/hvm/hvm.c
270@@ -3509,8 +3509,11 @@ static void hvm_s3_suspend(struct domain *d)
271
272 for_each_vcpu ( d, v )
273 {
274+ int rc;
275+
276 vlapic_reset(vcpu_vlapic(v));
277- vcpu_reset(v);
278+ rc = vcpu_reset(v);
279+ ASSERT(!rc);
280 }
281
282 vpic_reset(d);
283diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
284index 52d111b..7778342 100644
285--- a/xen/arch/x86/hvm/vlapic.c
286+++ b/xen/arch/x86/hvm/vlapic.c
287@@ -252,10 +252,13 @@ static void vlapic_init_sipi_action(unsigned long _vcpu)
288 {
289 case APIC_DM_INIT: {
290 bool_t fpu_initialised;
291+ int rc;
292+
293 domain_lock(target->domain);
294 /* Reset necessary VCPU state. This does not include FPU state. */
295 fpu_initialised = target->fpu_initialised;
296- vcpu_reset(target);
297+ rc = vcpu_reset(target);
298+ ASSERT(!rc);
299 target->fpu_initialised = fpu_initialised;
300 vlapic_reset(vcpu_vlapic(target));
301 domain_unlock(target->domain);
302diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
303index 8444610..055f307 100644
304--- a/xen/arch/x86/mm.c
305+++ b/xen/arch/x86/mm.c
306@@ -1241,7 +1241,16 @@ static int put_page_from_l3e(l3_pgentry_t l3e, unsigned long pfn,
307 #endif
308
309 if ( unlikely(partial > 0) )
310+ {
311+ ASSERT(preemptible >= 0);
312 return __put_page_type(l3e_get_page(l3e), preemptible);
313+ }
314+
315+ if ( preemptible < 0 )
316+ {
317+ current->arch.old_guest_table = l3e_get_page(l3e);
318+ return 0;
319+ }
320
321 return put_page_and_type_preemptible(l3e_get_page(l3e), preemptible);
322 }
323@@ -1254,7 +1263,17 @@ static int put_page_from_l4e(l4_pgentry_t l4e, unsigned long pfn,
324 (l4e_get_pfn(l4e) != pfn) )
325 {
326 if ( unlikely(partial > 0) )
327+ {
328+ ASSERT(preemptible >= 0);
329 return __put_page_type(l4e_get_page(l4e), preemptible);
330+ }
331+
332+ if ( preemptible < 0 )
333+ {
334+ current->arch.old_guest_table = l4e_get_page(l4e);
335+ return 0;
336+ }
337+
338 return put_page_and_type_preemptible(l4e_get_page(l4e), preemptible);
339 }
340 return 1;
341@@ -1549,12 +1568,17 @@ static int alloc_l3_table(struct page_info *page, int preemptible)
342 if ( rc < 0 && rc != -EAGAIN && rc != -EINTR )
343 {
344 MEM_LOG("Failure in alloc_l3_table: entry %d", i);
345+ if ( i )
346+ {
347+ page->nr_validated_ptes = i;
348+ page->partial_pte = 0;
349+ current->arch.old_guest_table = page;
350+ }
351 while ( i-- > 0 )
352 {
353 if ( !is_guest_l3_slot(i) )
354 continue;
355 unadjust_guest_l3e(pl3e[i], d);
356- put_page_from_l3e(pl3e[i], pfn, 0, 0);
357 }
358 }
359
360@@ -1584,22 +1608,24 @@ static int alloc_l4_table(struct page_info *page, int preemptible)
361 page->nr_validated_ptes = i;
362 page->partial_pte = partial ?: 1;
363 }
364- else if ( rc == -EINTR )
365+ else if ( rc < 0 )
366 {
367+ if ( rc != -EINTR )
368+ MEM_LOG("Failure in alloc_l4_table: entry %d", i);
369 if ( i )
370 {
371 page->nr_validated_ptes = i;
372 page->partial_pte = 0;
373- rc = -EAGAIN;
374+ if ( rc == -EINTR )
375+ rc = -EAGAIN;
376+ else
377+ {
378+ if ( current->arch.old_guest_table )
379+ page->nr_validated_ptes++;
380+ current->arch.old_guest_table = page;
381+ }
382 }
383 }
384- else if ( rc < 0 )
385- {
386- MEM_LOG("Failure in alloc_l4_table: entry %d", i);
387- while ( i-- > 0 )
388- if ( is_guest_l4_slot(d, i) )
389- put_page_from_l4e(pl4e[i], pfn, 0, 0);
390- }
391 if ( rc < 0 )
392 return rc;
393
394@@ -2047,7 +2073,7 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
395 pae_flush_pgd(pfn, pgentry_ptr_to_slot(pl3e), nl3e);
396 }
397
398- put_page_from_l3e(ol3e, pfn, 0, 0);
399+ put_page_from_l3e(ol3e, pfn, 0, -preemptible);
400 return rc;
401 }
402
403@@ -2110,7 +2136,7 @@ static int mod_l4_entry(l4_pgentry_t *pl4e,
404 return -EFAULT;
405 }
406
407- put_page_from_l4e(ol4e, pfn, 0, 0);
408+ put_page_from_l4e(ol4e, pfn, 0, -preemptible);
409 return rc;
410 }
411
412@@ -2268,7 +2294,15 @@ static int alloc_page_type(struct page_info *page, unsigned long type,
413 PRtype_info ": caf=%08lx taf=%" PRtype_info,
414 page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)),
415 type, page->count_info, page->u.inuse.type_info);
416- page->u.inuse.type_info = 0;
417+ if ( page != current->arch.old_guest_table )
418+ page->u.inuse.type_info = 0;
419+ else
420+ {
421+ ASSERT((page->u.inuse.type_info &
422+ (PGT_count_mask | PGT_validated)) == 1);
423+ get_page_light(page);
424+ page->u.inuse.type_info |= PGT_partial;
425+ }
426 }
427 else
428 {
429@@ -2808,49 +2842,150 @@ static void put_superpage(unsigned long mfn)
430
431 #endif
432
433+static int put_old_guest_table(struct vcpu *v)
434+{
435+ int rc;
436+
437+ if ( !v->arch.old_guest_table )
438+ return 0;
439+
440+ switch ( rc = put_page_and_type_preemptible(v->arch.old_guest_table, 1) )
441+ {
442+ case -EINTR:
443+ case -EAGAIN:
444+ return -EAGAIN;
445+ }
446+
447+ v->arch.old_guest_table = NULL;
448+
449+ return rc;
450+}
451+
452+int vcpu_destroy_pagetables(struct vcpu *v)
453+{
454+ unsigned long mfn = pagetable_get_pfn(v->arch.guest_table);
455+ struct page_info *page;
456+ int rc = put_old_guest_table(v);
457+
458+ if ( rc )
459+ return rc;
460+
461+#ifdef __x86_64__
462+ if ( is_pv_32on64_vcpu(v) )
463+ mfn = l4e_get_pfn(*(l4_pgentry_t *)mfn_to_virt(mfn));
464+#endif
465+
466+ if ( mfn )
467+ {
468+ page = mfn_to_page(mfn);
469+ if ( paging_mode_refcounts(v->domain) )
470+ put_page(page);
471+ else
472+ rc = put_page_and_type_preemptible(page, 1);
473+ }
474+
475+#ifdef __x86_64__
476+ if ( is_pv_32on64_vcpu(v) )
477+ {
478+ if ( !rc )
479+ l4e_write(
480+ (l4_pgentry_t *)__va(pagetable_get_paddr(v->arch.guest_table)),
481+ l4e_empty());
482+ }
483+ else
484+#endif
485+ if ( !rc )
486+ {
487+ v->arch.guest_table = pagetable_null();
488+
489+#ifdef __x86_64__
490+ /* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
491+ mfn = pagetable_get_pfn(v->arch.guest_table_user);
492+ if ( mfn )
493+ {
494+ page = mfn_to_page(mfn);
495+ if ( paging_mode_refcounts(v->domain) )
496+ put_page(page);
497+ else
498+ rc = put_page_and_type_preemptible(page, 1);
499+ }
500+ if ( !rc )
501+ v->arch.guest_table_user = pagetable_null();
502+#endif
503+ }
504+
505+ v->arch.cr3 = 0;
506+
507+ return rc;
508+}
509
510 int new_guest_cr3(unsigned long mfn)
511 {
512 struct vcpu *curr = current;
513 struct domain *d = curr->domain;
514- int okay;
515+ int rc;
516 unsigned long old_base_mfn;
517
518 #ifdef __x86_64__
519 if ( is_pv_32on64_domain(d) )
520 {
521- okay = paging_mode_refcounts(d)
522- ? 0 /* Old code was broken, but what should it be? */
523- : mod_l4_entry(
524+ rc = paging_mode_refcounts(d)
525+ ? -EINVAL /* Old code was broken, but what should it be? */
526+ : mod_l4_entry(
527 __va(pagetable_get_paddr(curr->arch.guest_table)),
528 l4e_from_pfn(
529 mfn,
530 (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)),
531- pagetable_get_pfn(curr->arch.guest_table), 0, 0, curr) == 0;
532- if ( unlikely(!okay) )
533+ pagetable_get_pfn(curr->arch.guest_table), 0, 1, curr);
534+ switch ( rc )
535 {
536+ case 0:
537+ break;
538+ case -EINTR:
539+ case -EAGAIN:
540+ return -EAGAIN;
541+ default:
542 MEM_LOG("Error while installing new compat baseptr %lx", mfn);
543- return 0;
544+ return rc;
545 }
546
547 invalidate_shadow_ldt(curr, 0);
548 write_ptbase(curr);
549
550- return 1;
551+ return 0;
552 }
553 #endif
554- okay = paging_mode_refcounts(d)
555- ? get_page_from_pagenr(mfn, d)
556- : !get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d, 0, 0);
557- if ( unlikely(!okay) )
558+ rc = put_old_guest_table(curr);
559+ if ( unlikely(rc) )
560+ return rc;
561+
562+ old_base_mfn = pagetable_get_pfn(curr->arch.guest_table);
563+ /*
564+ * This is particularly important when getting restarted after the
565+ * previous attempt got preempted in the put-old-MFN phase.
566+ */
567+ if ( old_base_mfn == mfn )
568 {
569- MEM_LOG("Error while installing new baseptr %lx", mfn);
570+ write_ptbase(curr);
571 return 0;
572 }
573
574- invalidate_shadow_ldt(curr, 0);
575+ rc = paging_mode_refcounts(d)
576+ ? (get_page_from_pagenr(mfn, d) ? 0 : -EINVAL)
577+ : get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d, 0, 1);
578+ switch ( rc )
579+ {
580+ case 0:
581+ break;
582+ case -EINTR:
583+ case -EAGAIN:
584+ return -EAGAIN;
585+ default:
586+ MEM_LOG("Error while installing new baseptr %lx", mfn);
587+ return rc;
588+ }
589
590- old_base_mfn = pagetable_get_pfn(curr->arch.guest_table);
591+ invalidate_shadow_ldt(curr, 0);
592
593 curr->arch.guest_table = pagetable_from_pfn(mfn);
594 update_cr3(curr);
595@@ -2859,13 +2994,25 @@ int new_guest_cr3(unsigned long mfn)
596
597 if ( likely(old_base_mfn != 0) )
598 {
599+ struct page_info *page = mfn_to_page(old_base_mfn);
600+
601 if ( paging_mode_refcounts(d) )
602- put_page(mfn_to_page(old_base_mfn));
603+ put_page(page);
604 else
605- put_page_and_type(mfn_to_page(old_base_mfn));
606+ switch ( rc = put_page_and_type_preemptible(page, 1) )
607+ {
608+ case -EINTR:
609+ rc = -EAGAIN;
610+ case -EAGAIN:
611+ curr->arch.old_guest_table = page;
612+ break;
613+ default:
614+ BUG_ON(rc);
615+ break;
616+ }
617 }
618
619- return 1;
620+ return rc;
621 }
622
623 static struct domain *get_pg_owner(domid_t domid)
624@@ -2994,12 +3141,29 @@ long do_mmuext_op(
625 unsigned int foreigndom)
626 {
627 struct mmuext_op op;
628- int rc = 0, i = 0, okay;
629 unsigned long type;
630- unsigned int done = 0;
631+ unsigned int i = 0, done = 0;
632 struct vcpu *curr = current;
633 struct domain *d = curr->domain;
634 struct domain *pg_owner;
635+ int okay, rc = put_old_guest_table(curr);
636+
637+ if ( unlikely(rc) )
638+ {
639+ if ( likely(rc == -EAGAIN) )
640+ rc = hypercall_create_continuation(
641+ __HYPERVISOR_mmuext_op, "hihi", uops, count, pdone,
642+ foreigndom);
643+ return rc;
644+ }
645+
646+ if ( unlikely(count == MMU_UPDATE_PREEMPTED) &&
647+ likely(guest_handle_is_null(uops)) )
648+ {
649+ /* See the curr->arch.old_guest_table related
650+ * hypercall_create_continuation() below. */
651+ return (int)foreigndom;
652+ }
653
654 if ( unlikely(count & MMU_UPDATE_PREEMPTED) )
655 {
656@@ -3024,7 +3188,7 @@ long do_mmuext_op(
657
658 for ( i = 0; i < count; i++ )
659 {
660- if ( hypercall_preempt_check() )
661+ if ( curr->arch.old_guest_table || hypercall_preempt_check() )
662 {
663 rc = -EAGAIN;
664 break;
665@@ -3088,21 +3252,17 @@ long do_mmuext_op(
666 }
667
668 if ( (rc = xsm_memory_pin_page(d, pg_owner, page)) != 0 )
669- {
670- put_page_and_type(page);
671 okay = 0;
672- break;
673- }
674-
675- if ( unlikely(test_and_set_bit(_PGT_pinned,
676- &page->u.inuse.type_info)) )
677+ else if ( unlikely(test_and_set_bit(_PGT_pinned,
678+ &page->u.inuse.type_info)) )
679 {
680 MEM_LOG("Mfn %lx already pinned", page_to_mfn(page));
681- put_page_and_type(page);
682 okay = 0;
683- break;
684 }
685
686+ if ( unlikely(!okay) )
687+ goto pin_drop;
688+
689 /* A page is dirtied when its pin status is set. */
690 paging_mark_dirty(pg_owner, page_to_mfn(page));
691
692@@ -3116,7 +3276,13 @@ long do_mmuext_op(
693 &page->u.inuse.type_info));
694 spin_unlock(&pg_owner->page_alloc_lock);
695 if ( drop_ref )
696- put_page_and_type(page);
697+ {
698+ pin_drop:
699+ if ( type == PGT_l1_page_table )
700+ put_page_and_type(page);
701+ else
702+ curr->arch.old_guest_table = page;
703+ }
704 }
705
706 break;
707@@ -3144,7 +3310,17 @@ long do_mmuext_op(
708 break;
709 }
710
711- put_page_and_type(page);
712+ switch ( rc = put_page_and_type_preemptible(page, 1) )
713+ {
714+ case -EINTR:
715+ case -EAGAIN:
716+ curr->arch.old_guest_table = page;
717+ rc = 0;
718+ break;
719+ default:
720+ BUG_ON(rc);
721+ break;
722+ }
723 put_page(page);
724
725 /* A page is dirtied when its pin status is cleared. */
726@@ -3154,8 +3330,13 @@ long do_mmuext_op(
727 }
728
729 case MMUEXT_NEW_BASEPTR:
730- okay = (!paging_mode_translate(d)
731- && new_guest_cr3(op.arg1.mfn));
732+ if ( paging_mode_translate(d) )
733+ okay = 0;
734+ else
735+ {
736+ rc = new_guest_cr3(op.arg1.mfn);
737+ okay = !rc;
738+ }
739 break;
740
741
742@@ -3169,29 +3350,56 @@ long do_mmuext_op(
743 break;
744 }
745
746+ old_mfn = pagetable_get_pfn(curr->arch.guest_table_user);
747+ /*
748+ * This is particularly important when getting restarted after the
749+ * previous attempt got preempted in the put-old-MFN phase.
750+ */
751+ if ( old_mfn == op.arg1.mfn )
752+ break;
753+
754 if ( op.arg1.mfn != 0 )
755 {
756 if ( paging_mode_refcounts(d) )
757 okay = get_page_from_pagenr(op.arg1.mfn, d);
758 else
759- okay = !get_page_and_type_from_pagenr(
760- op.arg1.mfn, PGT_root_page_table, d, 0, 0);
761+ {
762+ rc = get_page_and_type_from_pagenr(
763+ op.arg1.mfn, PGT_root_page_table, d, 0, 1);
764+ okay = !rc;
765+ }
766 if ( unlikely(!okay) )
767 {
768- MEM_LOG("Error while installing new mfn %lx", op.arg1.mfn);
769+ if ( rc == -EINTR )
770+ rc = -EAGAIN;
771+ else if ( rc != -EAGAIN )
772+ MEM_LOG("Error while installing new mfn %lx",
773+ op.arg1.mfn);
774 break;
775 }
776 }
777
778- old_mfn = pagetable_get_pfn(curr->arch.guest_table_user);
779 curr->arch.guest_table_user = pagetable_from_pfn(op.arg1.mfn);
780
781 if ( old_mfn != 0 )
782 {
783+ struct page_info *page = mfn_to_page(old_mfn);
784+
785 if ( paging_mode_refcounts(d) )
786- put_page(mfn_to_page(old_mfn));
787+ put_page(page);
788 else
789- put_page_and_type(mfn_to_page(old_mfn));
790+ switch ( rc = put_page_and_type_preemptible(page, 1) )
791+ {
792+ case -EINTR:
793+ rc = -EAGAIN;
794+ case -EAGAIN:
795+ curr->arch.old_guest_table = page;
796+ okay = 0;
797+ break;
798+ default:
799+ BUG_ON(rc);
800+ break;
801+ }
802 }
803
804 break;
805@@ -3433,9 +3641,27 @@ long do_mmuext_op(
806 }
807
808 if ( rc == -EAGAIN )
809+ {
810+ ASSERT(i < count);
811 rc = hypercall_create_continuation(
812 __HYPERVISOR_mmuext_op, "hihi",
813 uops, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
814+ }
815+ else if ( curr->arch.old_guest_table )
816+ {
817+ XEN_GUEST_HANDLE(void) null;
818+
819+ ASSERT(rc || i == count);
820+ set_xen_guest_handle(null, NULL);
821+ /*
822+ * In order to have a way to communicate the final return value to
823+ * our continuation, we pass this in place of "foreigndom", building
824+ * on the fact that this argument isn't needed anymore.
825+ */
826+ rc = hypercall_create_continuation(
827+ __HYPERVISOR_mmuext_op, "hihi", null,
828+ MMU_UPDATE_PREEMPTED, null, rc);
829+ }
830
831 put_pg_owner(pg_owner);
832
833@@ -3462,11 +3688,28 @@ long do_mmu_update(
834 void *va;
835 unsigned long gpfn, gmfn, mfn;
836 struct page_info *page;
837- int rc = 0, i = 0;
838- unsigned int cmd, done = 0, pt_dom;
839- struct vcpu *v = current;
840+ unsigned int cmd, i = 0, done = 0, pt_dom;
841+ struct vcpu *curr = current, *v = curr;
842 struct domain *d = v->domain, *pt_owner = d, *pg_owner;
843 struct domain_mmap_cache mapcache;
844+ int rc = put_old_guest_table(curr);
845+
846+ if ( unlikely(rc) )
847+ {
848+ if ( likely(rc == -EAGAIN) )
849+ rc = hypercall_create_continuation(
850+ __HYPERVISOR_mmu_update, "hihi", ureqs, count, pdone,
851+ foreigndom);
852+ return rc;
853+ }
854+
855+ if ( unlikely(count == MMU_UPDATE_PREEMPTED) &&
856+ likely(guest_handle_is_null(ureqs)) )
857+ {
858+ /* See the curr->arch.old_guest_table related
859+ * hypercall_create_continuation() below. */
860+ return (int)foreigndom;
861+ }
862
863 if ( unlikely(count & MMU_UPDATE_PREEMPTED) )
864 {
865@@ -3515,7 +3758,7 @@ long do_mmu_update(
866
867 for ( i = 0; i < count; i++ )
868 {
869- if ( hypercall_preempt_check() )
870+ if ( curr->arch.old_guest_table || hypercall_preempt_check() )
871 {
872 rc = -EAGAIN;
873 break;
874@@ -3696,9 +3939,27 @@ long do_mmu_update(
875 }
876
877 if ( rc == -EAGAIN )
878+ {
879+ ASSERT(i < count);
880 rc = hypercall_create_continuation(
881 __HYPERVISOR_mmu_update, "hihi",
882 ureqs, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
883+ }
884+ else if ( curr->arch.old_guest_table )
885+ {
886+ XEN_GUEST_HANDLE(void) null;
887+
888+ ASSERT(rc || i == count);
889+ set_xen_guest_handle(null, NULL);
890+ /*
891+ * In order to have a way to communicate the final return value to
892+ * our continuation, we pass this in place of "foreigndom", building
893+ * on the fact that this argument isn't needed anymore.
894+ */
895+ rc = hypercall_create_continuation(
896+ __HYPERVISOR_mmu_update, "hihi", null,
897+ MMU_UPDATE_PREEMPTED, null, rc);
898+ }
899
900 put_pg_owner(pg_owner);
901
902diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
903index 692281a..eada470 100644
904--- a/xen/arch/x86/traps.c
905+++ b/xen/arch/x86/traps.c
906@@ -2407,12 +2407,23 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
907 #endif
908 }
909 page = get_page_from_gfn(v->domain, gfn, NULL, P2M_ALLOC);
910- rc = page ? new_guest_cr3(page_to_mfn(page)) : 0;
911 if ( page )
912+ {
913+ rc = new_guest_cr3(page_to_mfn(page));
914 put_page(page);
915+ }
916+ else
917+ rc = -EINVAL;
918 domain_unlock(v->domain);
919- if ( rc == 0 ) /* not okay */
920+ switch ( rc )
921+ {
922+ case 0:
923+ break;
924+ case -EAGAIN: /* retry after preemption */
925+ goto skip;
926+ default: /* not okay */
927 goto fail;
928+ }
929 break;
930 }
931
932diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c
933index fb7baca..ef7822b 100644
934--- a/xen/arch/x86/x86_64/compat/mm.c
935+++ b/xen/arch/x86/x86_64/compat/mm.c
936@@ -268,6 +268,13 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mmuext_op_compat_t) cmp_uops,
937 int rc = 0;
938 XEN_GUEST_HANDLE(mmuext_op_t) nat_ops;
939
940+ if ( unlikely(count == MMU_UPDATE_PREEMPTED) &&
941+ likely(guest_handle_is_null(cmp_uops)) )
942+ {
943+ set_xen_guest_handle(nat_ops, NULL);
944+ return do_mmuext_op(nat_ops, count, pdone, foreigndom);
945+ }
946+
947 preempt_mask = count & MMU_UPDATE_PREEMPTED;
948 count ^= preempt_mask;
949
950@@ -365,17 +372,23 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mmuext_op_compat_t) cmp_uops,
951 : mcs->call.args[1];
952 unsigned int left = arg1 & ~MMU_UPDATE_PREEMPTED;
953
954- BUG_ON(left == arg1);
955+ BUG_ON(left == arg1 && left != i);
956 BUG_ON(left > count);
957 guest_handle_add_offset(nat_ops, i - left);
958 guest_handle_subtract_offset(cmp_uops, left);
959 left = 1;
960- BUG_ON(!hypercall_xlat_continuation(&left, 0x01, nat_ops, cmp_uops));
961- BUG_ON(left != arg1);
962- if (!test_bit(_MCSF_in_multicall, &mcs->flags))
963- regs->_ecx += count - i;
964+ if ( arg1 != MMU_UPDATE_PREEMPTED )
965+ {
966+ BUG_ON(!hypercall_xlat_continuation(&left, 0x01, nat_ops,
967+ cmp_uops));
968+ if ( !test_bit(_MCSF_in_multicall, &mcs->flags) )
969+ regs->_ecx += count - i;
970+ else
971+ mcs->compat_call.args[1] += count - i;
972+ }
973 else
974- mcs->compat_call.args[1] += count - i;
975+ BUG_ON(hypercall_xlat_continuation(&left, 0));
976+ BUG_ON(left != arg1);
977 }
978 else
979 BUG_ON(err > 0);
980diff --git a/xen/common/compat/domain.c b/xen/common/compat/domain.c
981index 40a0287..9ddaa38 100644
982--- a/xen/common/compat/domain.c
983+++ b/xen/common/compat/domain.c
984@@ -50,6 +50,10 @@ int compat_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
985 rc = v->is_initialised ? -EEXIST : arch_set_info_guest(v, cmp_ctxt);
986 domain_unlock(d);
987
988+ if ( rc == -EAGAIN )
989+ rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iih",
990+ cmd, vcpuid, arg);
991+
992 xfree(cmp_ctxt);
993 break;
994 }
995diff --git a/xen/common/domain.c b/xen/common/domain.c
996index c09fb73..89ab922 100644
997--- a/xen/common/domain.c
998+++ b/xen/common/domain.c
999@@ -779,14 +779,18 @@ void domain_unpause_by_systemcontroller(struct domain *d)
1000 domain_unpause(d);
1001 }
1002
1003-void vcpu_reset(struct vcpu *v)
1004+int vcpu_reset(struct vcpu *v)
1005 {
1006 struct domain *d = v->domain;
1007+ int rc;
1008
1009 vcpu_pause(v);
1010 domain_lock(d);
1011
1012- arch_vcpu_reset(v);
1013+ set_bit(_VPF_in_reset, &v->pause_flags);
1014+ rc = arch_vcpu_reset(v);
1015+ if ( rc )
1016+ goto out_unlock;
1017
1018 set_bit(_VPF_down, &v->pause_flags);
1019
1020@@ -802,9 +806,13 @@ void vcpu_reset(struct vcpu *v)
1021 #endif
1022 cpumask_clear(v->cpu_affinity_tmp);
1023 clear_bit(_VPF_blocked, &v->pause_flags);
1024+ clear_bit(_VPF_in_reset, &v->pause_flags);
1025
1026+ out_unlock:
1027 domain_unlock(v->domain);
1028 vcpu_unpause(v);
1029+
1030+ return rc;
1031 }
1032
1033
1034@@ -841,6 +849,11 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
1035 domain_unlock(d);
1036
1037 free_vcpu_guest_context(ctxt);
1038+
1039+ if ( rc == -EAGAIN )
1040+ rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iih",
1041+ cmd, vcpuid, arg);
1042+
1043 break;
1044
1045 case VCPUOP_up: {
1046diff --git a/xen/common/domctl.c b/xen/common/domctl.c
1047index cbc8146..b3bfb38 100644
1048--- a/xen/common/domctl.c
1049+++ b/xen/common/domctl.c
1050@@ -307,8 +307,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
1051
1052 if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
1053 {
1054- vcpu_reset(v);
1055- ret = 0;
1056+ ret = vcpu_reset(v);
1057+ if ( ret == -EAGAIN )
1058+ ret = hypercall_create_continuation(
1059+ __HYPERVISOR_domctl, "h", u_domctl);
1060 goto svc_out;
1061 }
1062
1063@@ -337,6 +339,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
1064 domain_pause(d);
1065 ret = arch_set_info_guest(v, c);
1066 domain_unpause(d);
1067+
1068+ if ( ret == -EAGAIN )
1069+ ret = hypercall_create_continuation(
1070+ __HYPERVISOR_domctl, "h", u_domctl);
1071 }
1072
1073 svc_out:
1074diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
1075index aecee68..898f63a 100644
1076--- a/xen/include/asm-x86/domain.h
1077+++ b/xen/include/asm-x86/domain.h
1078@@ -464,6 +464,7 @@ struct arch_vcpu
1079 pagetable_t guest_table_user; /* (MFN) x86/64 user-space pagetable */
1080 #endif
1081 pagetable_t guest_table; /* (MFN) guest notion of cr3 */
1082+ struct page_info *old_guest_table; /* partially destructed pagetable */
1083 /* guest_table holds a ref to the page, and also a type-count unless
1084 * shadow refcounts are in use */
1085 pagetable_t shadow_table[4]; /* (MFN) shadow(s) of guest */
1086diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
1087index ba92568..82cdde6 100644
1088--- a/xen/include/asm-x86/mm.h
1089+++ b/xen/include/asm-x86/mm.h
1090@@ -605,6 +605,7 @@ void audit_domains(void);
1091 int new_guest_cr3(unsigned long pfn);
1092 void make_cr3(struct vcpu *v, unsigned long mfn);
1093 void update_cr3(struct vcpu *v);
1094+int vcpu_destroy_pagetables(struct vcpu *);
1095 void propagate_page_fault(unsigned long addr, u16 error_code);
1096 void *do_page_walk(struct vcpu *v, unsigned long addr);
1097
1098diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
1099index d4ac50f..504a70f 100644
1100--- a/xen/include/xen/domain.h
1101+++ b/xen/include/xen/domain.h
1102@@ -13,7 +13,7 @@ typedef union {
1103 struct vcpu *alloc_vcpu(
1104 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id);
1105 struct vcpu *alloc_dom0_vcpu0(void);
1106-void vcpu_reset(struct vcpu *v);
1107+int vcpu_reset(struct vcpu *);
1108
1109 struct xen_domctl_getdomaininfo;
1110 void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info);
1111@@ -67,7 +67,7 @@ void arch_dump_vcpu_info(struct vcpu *v);
1112
1113 void arch_dump_domain_info(struct domain *d);
1114
1115-void arch_vcpu_reset(struct vcpu *v);
1116+int arch_vcpu_reset(struct vcpu *);
1117
1118 extern spinlock_t vcpu_alloc_lock;
1119 bool_t domctl_lock_acquire(void);
1120diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
1121index b619269..b0715cb 100644
1122--- a/xen/include/xen/sched.h
1123+++ b/xen/include/xen/sched.h
1124@@ -644,6 +644,9 @@ static inline struct domain *next_domain_in_cpupool(
1125 /* VCPU is blocked due to missing mem_sharing ring. */
1126 #define _VPF_mem_sharing 6
1127 #define VPF_mem_sharing (1UL<<_VPF_mem_sharing)
1128+ /* VCPU is being reset. */
1129+#define _VPF_in_reset 7
1130+#define VPF_in_reset (1UL<<_VPF_in_reset)
1131
1132 static inline int vcpu_runnable(struct vcpu *v)
1133 {
diff --git a/main/xen/xsa58-4.2.patch b/main/xen/xsa58-4.2.patch
new file mode 100644
index 0000000000..1ea3aaa97d
--- /dev/null
+++ b/main/xen/xsa58-4.2.patch
@@ -0,0 +1,129 @@
1x86: fix page refcount handling in page table pin error path
2
3In the original patch 7 of the series addressing XSA-45 I mistakenly
4took the addition of the call to get_page_light() in alloc_page_type()
5to cover two decrements that would happen: One for the PGT_partial bit
6that is getting set along with the call, and the other for the page
7reference the caller hold (and would be dropping on its error path).
8But of course the additional page reference is tied to the PGT_partial
9bit, and hence any caller of a function that may leave
10->arch.old_guest_table non-NULL for error cleanup purposes has to make
11sure a respective page reference gets retained.
12
13Similar issues were then also spotted elsewhere: In effect all callers
14of get_page_type_preemptible() need to deal with errors in similar
15ways. To make sure error handling can work this way without leaking
16page references, a respective assertion gets added to that function.
17
18This is CVE-2013-1432 / XSA-58.
19
20Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
21Signed-off-by: Jan Beulich <jbeulich@suse.com>
22Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>
23Reviewed-by: Tim Deegan <tim@xen.org>
24
25--- a/xen/arch/x86/domain.c
26+++ b/xen/arch/x86/domain.c
27@@ -941,6 +941,10 @@ int arch_set_info_guest(
28 if ( v->vcpu_id == 0 )
29 d->vm_assist = c(vm_assist);
30
31+ rc = put_old_guest_table(current);
32+ if ( rc )
33+ return rc;
34+
35 if ( !compat )
36 rc = (int)set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
37 #ifdef CONFIG_COMPAT
38@@ -980,18 +984,24 @@ int arch_set_info_guest(
39 }
40 else
41 {
42- /*
43- * Since v->arch.guest_table{,_user} are both NULL, this effectively
44- * is just a call to put_old_guest_table().
45- */
46 if ( !compat )
47- rc = vcpu_destroy_pagetables(v);
48+ rc = put_old_guest_table(v);
49 if ( !rc )
50 rc = get_page_type_preemptible(cr3_page,
51 !compat ? PGT_root_page_table
52 : PGT_l3_page_table);
53- if ( rc == -EINTR )
54+ switch ( rc )
55+ {
56+ case -EINTR:
57 rc = -EAGAIN;
58+ case -EAGAIN:
59+ case 0:
60+ break;
61+ default:
62+ if ( cr3_page == current->arch.old_guest_table )
63+ cr3_page = NULL;
64+ break;
65+ }
66 }
67 if ( rc )
68 /* handled below */;
69@@ -1018,6 +1028,11 @@ int arch_set_info_guest(
70 pagetable_get_page(v->arch.guest_table);
71 v->arch.guest_table = pagetable_null();
72 break;
73+ default:
74+ if ( cr3_page == current->arch.old_guest_table )
75+ cr3_page = NULL;
76+ case 0:
77+ break;
78 }
79 }
80 if ( !rc )
81--- a/xen/arch/x86/mm.c
82+++ b/xen/arch/x86/mm.c
83@@ -718,7 +718,8 @@ static int get_page_and_type_from_pagenr
84 get_page_type_preemptible(page, type) :
85 (get_page_type(page, type) ? 0 : -EINVAL));
86
87- if ( unlikely(rc) && partial >= 0 )
88+ if ( unlikely(rc) && partial >= 0 &&
89+ (!preemptible || page != current->arch.old_guest_table) )
90 put_page(page);
91
92 return rc;
93@@ -2638,6 +2639,7 @@ int put_page_type_preemptible(struct pag
94
95 int get_page_type_preemptible(struct page_info *page, unsigned long type)
96 {
97+ ASSERT(!current->arch.old_guest_table);
98 return __get_page_type(page, type, 1);
99 }
100
101@@ -2848,7 +2850,7 @@ static void put_superpage(unsigned long
102
103 #endif
104
105-static int put_old_guest_table(struct vcpu *v)
106+int put_old_guest_table(struct vcpu *v)
107 {
108 int rc;
109
110@@ -3253,7 +3255,8 @@ long do_mmuext_op(
111 rc = -EAGAIN;
112 else if ( rc != -EAGAIN )
113 MEM_LOG("Error while pinning mfn %lx", page_to_mfn(page));
114- put_page(page);
115+ if ( page != curr->arch.old_guest_table )
116+ put_page(page);
117 break;
118 }
119
120--- a/xen/include/asm-x86/mm.h
121+++ b/xen/include/asm-x86/mm.h
122@@ -374,6 +374,7 @@ void put_page_type(struct page_info *pag
123 int get_page_type(struct page_info *page, unsigned long type);
124 int put_page_type_preemptible(struct page_info *page);
125 int get_page_type_preemptible(struct page_info *page, unsigned long type);
126+int put_old_guest_table(struct vcpu *);
127 int get_page_from_l1e(
128 l1_pgentry_t l1e, struct domain *l1e_owner, struct domain *pg_owner);
129 void put_page_from_l1e(l1_pgentry_t l1e, struct domain *l1e_owner);