]>
Commit | Line | Data |
---|---|---|
23d51c33 JR |
1 | Description: x86: make vcpu_reset() preemptible |
2 | ... as dropping the old page tables may take significant amounts of | |
3 | time. | |
4 | From: Jan Beulich <jbeulich@suse.com> | |
5 | Origin: upstream | |
6 | Id: CVE-2013-1918 XSA-45 | |
7 | --- | |
8 | --- a/xen/arch/x86/domain.c | |
9 | +++ b/xen/arch/x86/domain.c | |
10 | @@ -1051,17 +1051,16 @@ int arch_set_info_guest( | |
11 | #undef c | |
12 | } | |
13 | ||
14 | -void arch_vcpu_reset(struct vcpu *v) | |
15 | +int arch_vcpu_reset(struct vcpu *v) | |
16 | { | |
17 | if ( !is_hvm_vcpu(v) ) | |
18 | { | |
19 | destroy_gdt(v); | |
20 | - vcpu_destroy_pagetables(v, 0); | |
21 | - } | |
22 | - else | |
23 | - { | |
24 | - vcpu_end_shutdown_deferral(v); | |
25 | + return vcpu_destroy_pagetables(v); | |
26 | } | |
27 | + | |
28 | + vcpu_end_shutdown_deferral(v); | |
29 | + return 0; | |
30 | } | |
31 | ||
32 | /* | |
33 | @@ -2085,7 +2084,7 @@ int domain_relinquish_resources(struct domain *d) | |
34 | /* Drop the in-use references to page-table bases. */ | |
35 | for_each_vcpu ( d, v ) | |
36 | { | |
37 | - ret = vcpu_destroy_pagetables(v, 1); | |
38 | + ret = vcpu_destroy_pagetables(v); | |
39 | if ( ret ) | |
40 | return ret; | |
41 | } | |
42 | --- a/xen/arch/x86/hvm/hvm.c | |
43 | +++ b/xen/arch/x86/hvm/hvm.c | |
44 | @@ -3509,8 +3509,11 @@ static void hvm_s3_suspend(struct domain *d) | |
45 | ||
46 | for_each_vcpu ( d, v ) | |
47 | { | |
48 | + int rc; | |
49 | + | |
50 | vlapic_reset(vcpu_vlapic(v)); | |
51 | - vcpu_reset(v); | |
52 | + rc = vcpu_reset(v); | |
53 | + ASSERT(!rc); | |
54 | } | |
55 | ||
56 | vpic_reset(d); | |
57 | --- a/xen/arch/x86/hvm/vlapic.c | |
58 | +++ b/xen/arch/x86/hvm/vlapic.c | |
59 | @@ -252,10 +252,13 @@ static void vlapic_init_sipi_action(unsigned long _vcpu) | |
60 | { | |
61 | case APIC_DM_INIT: { | |
62 | bool_t fpu_initialised; | |
63 | + int rc; | |
64 | + | |
65 | domain_lock(target->domain); | |
66 | /* Reset necessary VCPU state. This does not include FPU state. */ | |
67 | fpu_initialised = target->fpu_initialised; | |
68 | - vcpu_reset(target); | |
69 | + rc = vcpu_reset(target); | |
70 | + ASSERT(!rc); | |
71 | target->fpu_initialised = fpu_initialised; | |
72 | vlapic_reset(vcpu_vlapic(target)); | |
73 | domain_unlock(target->domain); | |
74 | --- a/xen/arch/x86/mm.c | |
75 | +++ b/xen/arch/x86/mm.c | |
76 | @@ -2827,7 +2827,7 @@ static int put_old_guest_table(struct vcpu *v) | |
77 | return rc; | |
78 | } | |
79 | ||
80 | -int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible) | |
81 | +int vcpu_destroy_pagetables(struct vcpu *v) | |
82 | { | |
83 | unsigned long mfn = pagetable_get_pfn(v->arch.guest_table); | |
84 | struct page_info *page; | |
85 | @@ -2847,7 +2847,7 @@ int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible) | |
86 | if ( paging_mode_refcounts(v->domain) ) | |
87 | put_page(page); | |
88 | else | |
89 | - rc = put_page_and_type_preemptible(page, preemptible); | |
90 | + rc = put_page_and_type_preemptible(page, 1); | |
91 | } | |
92 | ||
93 | #ifdef __x86_64__ | |
94 | @@ -2873,7 +2873,7 @@ int vcpu_destroy_pagetables(struct vcpu *v, bool_t preemptible) | |
95 | if ( paging_mode_refcounts(v->domain) ) | |
96 | put_page(page); | |
97 | else | |
98 | - rc = put_page_and_type_preemptible(page, preemptible); | |
99 | + rc = put_page_and_type_preemptible(page, 1); | |
100 | } | |
101 | if ( !rc ) | |
102 | v->arch.guest_table_user = pagetable_null(); | |
103 | --- a/xen/common/domain.c | |
104 | +++ b/xen/common/domain.c | |
105 | @@ -779,14 +779,18 @@ void domain_unpause_by_systemcontroller(struct domain *d) | |
106 | domain_unpause(d); | |
107 | } | |
108 | ||
109 | -void vcpu_reset(struct vcpu *v) | |
110 | +int vcpu_reset(struct vcpu *v) | |
111 | { | |
112 | struct domain *d = v->domain; | |
113 | + int rc; | |
114 | ||
115 | vcpu_pause(v); | |
116 | domain_lock(d); | |
117 | ||
118 | - arch_vcpu_reset(v); | |
119 | + set_bit(_VPF_in_reset, &v->pause_flags); | |
120 | + rc = arch_vcpu_reset(v); | |
121 | + if ( rc ) | |
122 | + goto out_unlock; | |
123 | ||
124 | set_bit(_VPF_down, &v->pause_flags); | |
125 | ||
126 | @@ -802,9 +806,13 @@ void vcpu_reset(struct vcpu *v) | |
127 | #endif | |
128 | cpumask_clear(v->cpu_affinity_tmp); | |
129 | clear_bit(_VPF_blocked, &v->pause_flags); | |
130 | + clear_bit(_VPF_in_reset, &v->pause_flags); | |
131 | ||
132 | + out_unlock: | |
133 | domain_unlock(v->domain); | |
134 | vcpu_unpause(v); | |
135 | + | |
136 | + return rc; | |
137 | } | |
138 | ||
139 | ||
140 | --- a/xen/common/domctl.c | |
141 | +++ b/xen/common/domctl.c | |
142 | @@ -307,8 +307,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) | |
143 | ||
144 | if ( guest_handle_is_null(op->u.vcpucontext.ctxt) ) | |
145 | { | |
146 | - vcpu_reset(v); | |
147 | - ret = 0; | |
148 | + ret = vcpu_reset(v); | |
149 | + if ( ret == -EAGAIN ) | |
150 | + ret = hypercall_create_continuation( | |
151 | + __HYPERVISOR_domctl, "h", u_domctl); | |
152 | goto svc_out; | |
153 | } | |
154 | ||
155 | --- a/xen/include/asm-x86/mm.h | |
156 | +++ b/xen/include/asm-x86/mm.h | |
157 | @@ -605,7 +605,7 @@ void audit_domains(void); | |
158 | int new_guest_cr3(unsigned long pfn); | |
159 | void make_cr3(struct vcpu *v, unsigned long mfn); | |
160 | void update_cr3(struct vcpu *v); | |
161 | -int vcpu_destroy_pagetables(struct vcpu *, bool_t preemptible); | |
162 | +int vcpu_destroy_pagetables(struct vcpu *); | |
163 | void propagate_page_fault(unsigned long addr, u16 error_code); | |
164 | void *do_page_walk(struct vcpu *v, unsigned long addr); | |
165 | ||
166 | --- a/xen/include/xen/domain.h | |
167 | +++ b/xen/include/xen/domain.h | |
168 | @@ -13,7 +13,7 @@ typedef union { | |
169 | struct vcpu *alloc_vcpu( | |
170 | struct domain *d, unsigned int vcpu_id, unsigned int cpu_id); | |
171 | struct vcpu *alloc_dom0_vcpu0(void); | |
172 | -void vcpu_reset(struct vcpu *v); | |
173 | +int vcpu_reset(struct vcpu *); | |
174 | ||
175 | struct xen_domctl_getdomaininfo; | |
176 | void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info); | |
177 | @@ -67,7 +67,7 @@ void arch_dump_vcpu_info(struct vcpu *v); | |
178 | ||
179 | void arch_dump_domain_info(struct domain *d); | |
180 | ||
181 | -void arch_vcpu_reset(struct vcpu *v); | |
182 | +int arch_vcpu_reset(struct vcpu *); | |
183 | ||
184 | extern spinlock_t vcpu_alloc_lock; | |
185 | bool_t domctl_lock_acquire(void); | |
186 | --- a/xen/include/xen/sched.h | |
187 | +++ b/xen/include/xen/sched.h | |
188 | @@ -644,6 +644,9 @@ static inline struct domain *next_domain_in_cpupool( | |
189 | /* VCPU is blocked due to missing mem_sharing ring. */ | |
190 | #define _VPF_mem_sharing 6 | |
191 | #define VPF_mem_sharing (1UL<<_VPF_mem_sharing) | |
192 | + /* VCPU is being reset. */ | |
193 | +#define _VPF_in_reset 7 | |
194 | +#define VPF_in_reset (1UL<<_VPF_in_reset) | |
195 | ||
196 | static inline int vcpu_runnable(struct vcpu *v) | |
197 | { |