diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2013-07-01 14:38:45 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2013-07-01 14:44:49 +0000 |
commit | ccdb8c3a1257db6b1ceb3af663b239003a047fd3 (patch) | |
tree | 55359f18760f9b250978f861185fd3ac9aa979ba | |
parent | 02bb9229c574679953a432211e3a4590ecda8419 (diff) | |
download | alpine_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/APKBUILD | 10 | ||||
-rw-r--r-- | main/xen/xsa45-4.2.patch | 1133 | ||||
-rw-r--r-- | main/xen/xsa58-4.2.patch | 129 |
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> |
4 | pkgname=xen | 4 | pkgname=xen |
5 | pkgver=4.2.2 | 5 | pkgver=4.2.2 |
6 | pkgrel=4 | 6 | pkgrel=5 |
7 | pkgdesc="Xen hypervisor" | 7 | pkgdesc="Xen hypervisor" |
8 | url="http://www.xen.org/" | 8 | url="http://www.xen.org/" |
9 | arch="x86 x86_64" | 9 | arch="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 | |||
153 | 8ad8942000b8a4be4917599cad9209cf xsa41.patch | 155 | 8ad8942000b8a4be4917599cad9209cf xsa41.patch |
154 | ed7d0399c6ca6aeee479da5d8f807fe0 xsa41b.patch | 156 | ed7d0399c6ca6aeee479da5d8f807fe0 xsa41b.patch |
155 | 2f3dd7bdc59d104370066d6582725575 xsa41c.patch | 157 | 2f3dd7bdc59d104370066d6582725575 xsa41c.patch |
158 | 9265540493f41f7d40c48d0886ec5823 xsa45-4.2.patch | ||
156 | b3e3a57d189a4f86c9766eaf3b5207f4 xsa48-4.2.patch | 159 | b3e3a57d189a4f86c9766eaf3b5207f4 xsa48-4.2.patch |
157 | 83a9cdd035bcd18bf035434a1ba08c38 xsa52-4.2-unstable.patch | 160 | 83a9cdd035bcd18bf035434a1ba08c38 xsa52-4.2-unstable.patch |
158 | 03a1a4ebc470ee7e638e04db2701a4f7 xsa53-4.2.patch | 161 | 03a1a4ebc470ee7e638e04db2701a4f7 xsa53-4.2.patch |
@@ -160,6 +163,7 @@ a8393d1ec6b886ea72ffe624a04ee10a xsa54.patch | |||
160 | 42cd104f2a33d67938a63a6372cff573 xsa55.patch | 163 | 42cd104f2a33d67938a63a6372cff573 xsa55.patch |
161 | e70b9128ffc2175cea314a533a7d8457 xsa56.patch | 164 | e70b9128ffc2175cea314a533a7d8457 xsa56.patch |
162 | 7475158130474ee062a4eb878259af61 xsa57.patch | 165 | 7475158130474ee062a4eb878259af61 xsa57.patch |
166 | 7de2cd11c10d6a554f3c81e0688c38b7 xsa58-4.2.patch | ||
163 | c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch | 167 | c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch |
164 | 95d8af17bf844d41a015ff32aae51ba1 xenstored.initd | 168 | 95d8af17bf844d41a015ff32aae51ba1 xenstored.initd |
165 | b017ccdd5e1c27bbf1513e3569d4ff07 xenstored.confd | 169 | b017ccdd5e1c27bbf1513e3569d4ff07 xenstored.confd |
@@ -180,6 +184,7 @@ a0c225d716d343fe041b63e3940900c5b3573ed3bcfc5b7c2d52ea2861c3fc28 docs-Fix-gener | |||
180 | 93452beba88a8da8e89b8bfa743074a358ba1d9052151c608e21c4d62f8c4867 xsa41.patch | 184 | 93452beba88a8da8e89b8bfa743074a358ba1d9052151c608e21c4d62f8c4867 xsa41.patch |
181 | 896a07f57310c9bea9bc2a305166cf796282c381cb7839be49105b1726a860b5 xsa41b.patch | 185 | 896a07f57310c9bea9bc2a305166cf796282c381cb7839be49105b1726a860b5 xsa41b.patch |
182 | 683dd96a0a8899f794070c8c09643dfeeb39f92da531955cba961b45f6075914 xsa41c.patch | 186 | 683dd96a0a8899f794070c8c09643dfeeb39f92da531955cba961b45f6075914 xsa41c.patch |
187 | f3c8c75cc6f55409139b1928017d1e432e5e64b6fac2083395f4723353e1c775 xsa45-4.2.patch | ||
183 | dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patch | 188 | dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patch |
184 | 5b8582185bf90386729e81db1f7780c69a891b074a87d9a619a90d6f639bea13 xsa52-4.2-unstable.patch | 189 | 5b8582185bf90386729e81db1f7780c69a891b074a87d9a619a90d6f639bea13 xsa52-4.2-unstable.patch |
185 | 785f7612bd229f7501f4e98e4760f307d90c64305ee14707d262b77f05fa683d xsa53-4.2.patch | 190 | 785f7612bd229f7501f4e98e4760f307d90c64305ee14707d262b77f05fa683d xsa53-4.2.patch |
@@ -187,6 +192,7 @@ dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patc | |||
187 | ac3ebaf3ec37e28ba08e23d63626d7aaccf0a3f282dd0af9c24cc4df3fd8fae0 xsa55.patch | 192 | ac3ebaf3ec37e28ba08e23d63626d7aaccf0a3f282dd0af9c24cc4df3fd8fae0 xsa55.patch |
188 | a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch | 193 | a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch |
189 | b6a5106848541972519cc529859d9ff3083c79367276c7031560fa4ce6f9f770 xsa57.patch | 194 | b6a5106848541972519cc529859d9ff3083c79367276c7031560fa4ce6f9f770 xsa57.patch |
195 | 194d6610fc38b767d643e5d58a1268f45921fb35e309b47aca6a388b861311c2 xsa58-4.2.patch | ||
190 | b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch | 196 | b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch |
191 | 81d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd | 197 | 81d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd |
192 | ea9171e71ab3d33061979bcf3bb737156192aa4b0be4d1234438ced75b6fdef3 xenstored.confd | 198 | ea9171e71ab3d33061979bcf3bb737156192aa4b0be4d1234438ced75b6fdef3 xenstored.confd |
@@ -207,6 +213,7 @@ sha512sums="4943b18016ed8c2b194a3b55e6655b3b734b39ffb8cb7ee0a0580f2f4460a1d0e92e | |||
207 | 94672a4d37db4e370370157cac9507ee1a75832f4be779fba148c1faa0b18f26ed57126eee6256ccd5d218463325a730266b53139554f4865adedb7659154c16 xsa41.patch | 213 | 94672a4d37db4e370370157cac9507ee1a75832f4be779fba148c1faa0b18f26ed57126eee6256ccd5d218463325a730266b53139554f4865adedb7659154c16 xsa41.patch |
208 | bda9105793f2327e1317991762120d0668af0e964076b18c9fdbfd509984b2e88d85df95702c46b2e00d5350e8113f6aa7b34b19064d19abbeb4d43f0c431d38 xsa41b.patch | 214 | bda9105793f2327e1317991762120d0668af0e964076b18c9fdbfd509984b2e88d85df95702c46b2e00d5350e8113f6aa7b34b19064d19abbeb4d43f0c431d38 xsa41b.patch |
209 | 36b60478660ff7748328f5ab9adff13286eee1a1bad06e42fdf7e6aafe105103988525725aacd660cf5b2a184a9e2d6b3818655203c1fa07e07dcebdf23f35d9 xsa41c.patch | 215 | 36b60478660ff7748328f5ab9adff13286eee1a1bad06e42fdf7e6aafe105103988525725aacd660cf5b2a184a9e2d6b3818655203c1fa07e07dcebdf23f35d9 xsa41c.patch |
216 | a57b4c8be76a938d51e51ffb39f0781389ebef320f359b0ae9af4a93af970d37dde50a304d4864a75b7fb32861a4745b9da5fa6acce0f2a688b11b13ab43fb4e xsa45-4.2.patch | ||
210 | 31dd8c62d41cc0a01a79d9b24a5b793f5e2058230808d9c5364c6ff3477ab02f3258f1bbd761d97dc1b97ee120b41524b999eaac77f33b606496fc324b5fa2e4 xsa48-4.2.patch | 217 | 31dd8c62d41cc0a01a79d9b24a5b793f5e2058230808d9c5364c6ff3477ab02f3258f1bbd761d97dc1b97ee120b41524b999eaac77f33b606496fc324b5fa2e4 xsa48-4.2.patch |
211 | b64a965fab8534958e453c493211ed3a6555aafb90d18f6d56a45b41d3086a0029aee85b6b6eb93b0d861d5fdc0ef10fc32e9b4f83593b37c43922d838085dd8 xsa52-4.2-unstable.patch | 218 | b64a965fab8534958e453c493211ed3a6555aafb90d18f6d56a45b41d3086a0029aee85b6b6eb93b0d861d5fdc0ef10fc32e9b4f83593b37c43922d838085dd8 xsa52-4.2-unstable.patch |
212 | 9b08924e563e79d2b308c1521da520c0579b334b61ac99a5593eabdb96dbda2da898b542cc47bda6d663c68343216d9d29c04853b6d1b6ecdde964b0cbb3f7ab xsa53-4.2.patch | 219 | 9b08924e563e79d2b308c1521da520c0579b334b61ac99a5593eabdb96dbda2da898b542cc47bda6d663c68343216d9d29c04853b6d1b6ecdde964b0cbb3f7ab xsa53-4.2.patch |
@@ -214,6 +221,7 @@ c9010be637d4f96ef03c880e1ef28228f762c5980108380a105bd190b631a882c8dff81e9421246d | |||
214 | b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a08797271a3dbc756d3f705a990991c8d2fc96f0f272c3665a xsa55.patch | 221 | b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a08797271a3dbc756d3f705a990991c8d2fc96f0f272c3665a xsa55.patch |
215 | 26a1c2cc92ddd4c1ab6712b0e41a0135d0e76a7fe3a14b651fb0235e352e5a24077414371acccb93058b7ce4d882b667386811170ba74570c53165837bcd983d xsa56.patch | 222 | 26a1c2cc92ddd4c1ab6712b0e41a0135d0e76a7fe3a14b651fb0235e352e5a24077414371acccb93058b7ce4d882b667386811170ba74570c53165837bcd983d xsa56.patch |
216 | 5ccc1654d9f0270485495f9fc913e41663ddbda602ffe049e0a9c3247c6246690b7ec4165482f96921c5253a2a5205ca384048339996e611c07ab60a6a75cf6a xsa57.patch | 223 | 5ccc1654d9f0270485495f9fc913e41663ddbda602ffe049e0a9c3247c6246690b7ec4165482f96921c5253a2a5205ca384048339996e611c07ab60a6a75cf6a xsa57.patch |
224 | 60813c01f6bb909da8748919df4d0ffa923baf4b7b55287e0bec3389fb83020158225182e112941c9e126b4df57e7b8724f2a69d0c1fa9ce3b37c0bdf1a49da4 xsa58-4.2.patch | ||
217 | ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch | 225 | ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch |
218 | 792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd | 226 | 792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd |
219 | 100cf4112f401f45c1e4e885a5074698c484b40521262f6268fad286498e95f4c51e746f0e94eb43a590bb8e813a397bb53801ccacebec9541020799d8d70514 xenstored.confd | 227 | 100cf4112f401f45c1e4e885a5074698c484b40521262f6268fad286498e95f4c51e746f0e94eb43a590bb8e813a397bb53801ccacebec9541020799d8d70514 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 @@ | |||
1 | diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c | ||
2 | index 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 | { | ||
266 | diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c | ||
267 | index 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); | ||
283 | diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c | ||
284 | index 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); | ||
302 | diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c | ||
303 | index 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 | |||
902 | diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c | ||
903 | index 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 | |||
932 | diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c | ||
933 | index 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); | ||
980 | diff --git a/xen/common/compat/domain.c b/xen/common/compat/domain.c | ||
981 | index 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 | } | ||
995 | diff --git a/xen/common/domain.c b/xen/common/domain.c | ||
996 | index 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: { | ||
1046 | diff --git a/xen/common/domctl.c b/xen/common/domctl.c | ||
1047 | index 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: | ||
1074 | diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h | ||
1075 | index 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 */ | ||
1086 | diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h | ||
1087 | index 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 | |||
1098 | diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h | ||
1099 | index 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); | ||
1120 | diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h | ||
1121 | index 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 @@ | |||
1 | x86: fix page refcount handling in page table pin error path | ||
2 | |||
3 | In the original patch 7 of the series addressing XSA-45 I mistakenly | ||
4 | took the addition of the call to get_page_light() in alloc_page_type() | ||
5 | to cover two decrements that would happen: One for the PGT_partial bit | ||
6 | that is getting set along with the call, and the other for the page | ||
7 | reference the caller hold (and would be dropping on its error path). | ||
8 | But of course the additional page reference is tied to the PGT_partial | ||
9 | bit, and hence any caller of a function that may leave | ||
10 | ->arch.old_guest_table non-NULL for error cleanup purposes has to make | ||
11 | sure a respective page reference gets retained. | ||
12 | |||
13 | Similar issues were then also spotted elsewhere: In effect all callers | ||
14 | of get_page_type_preemptible() need to deal with errors in similar | ||
15 | ways. To make sure error handling can work this way without leaking | ||
16 | page references, a respective assertion gets added to that function. | ||
17 | |||
18 | This is CVE-2013-1432 / XSA-58. | ||
19 | |||
20 | Reported-by: Andrew Cooper <andrew.cooper3@citrix.com> | ||
21 | Signed-off-by: Jan Beulich <jbeulich@suse.com> | ||
22 | Tested-by: Andrew Cooper <andrew.cooper3@citrix.com> | ||
23 | Reviewed-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); | ||