@@ -133,32 +133,57 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *v, int state)
133
133
void kvm_xen_update_runstate_guest (struct kvm_vcpu * v , int state )
134
134
{
135
135
struct kvm_vcpu_xen * vx = & v -> arch .xen ;
136
+ struct gfn_to_hva_cache * ghc = & vx -> runstate_cache ;
137
+ struct kvm_memslots * slots = kvm_memslots (v -> kvm );
138
+ bool atomic = (state == RUNSTATE_runnable );
136
139
uint64_t state_entry_time ;
137
- unsigned int offset ;
140
+ int __user * user_state ;
141
+ uint64_t __user * user_times ;
138
142
139
143
kvm_xen_update_runstate (v , state );
140
144
141
145
if (!vx -> runstate_set )
142
146
return ;
143
147
144
- BUILD_BUG_ON (sizeof (struct compat_vcpu_runstate_info ) != 0x2c );
148
+ if (unlikely (slots -> generation != ghc -> generation || kvm_is_error_hva (ghc -> hva )) &&
149
+ kvm_gfn_to_hva_cache_init (v -> kvm , ghc , ghc -> gpa , ghc -> len ))
150
+ return ;
151
+
152
+ /* We made sure it fits in a single page */
153
+ BUG_ON (!ghc -> memslot );
154
+
155
+ if (atomic )
156
+ pagefault_disable ();
145
157
146
- offset = offsetof(struct compat_vcpu_runstate_info , state_entry_time );
147
- #ifdef CONFIG_X86_64
148
158
/*
149
- * The only difference is alignment of uint64_t in 32-bit.
150
- * So the first field 'state' is accessed directly using
151
- * offsetof() (where its offset happens to be zero), while the
152
- * remaining fields which are all uint64_t, start at 'offset'
153
- * which we tweak here by adding 4.
159
+ * The only difference between 32-bit and 64-bit versions of the
160
+ * runstate struct us the alignment of uint64_t in 32-bit, which
161
+ * means that the 64-bit version has an additional 4 bytes of
162
+ * padding after the first field 'state'.
163
+ *
164
+ * So we use 'int __user *user_state' to point to the state field,
165
+ * and 'uint64_t __user *user_times' for runstate_entry_time. So
166
+ * the actual array of time[] in each state starts at user_times[1].
154
167
*/
168
+ BUILD_BUG_ON (offsetof(struct vcpu_runstate_info , state ) != 0 );
169
+ BUILD_BUG_ON (offsetof(struct compat_vcpu_runstate_info , state ) != 0 );
170
+ user_state = (int __user * )ghc -> hva ;
171
+
172
+ BUILD_BUG_ON (sizeof (struct compat_vcpu_runstate_info ) != 0x2c );
173
+
174
+ user_times = (uint64_t __user * )(ghc -> hva +
175
+ offsetof(struct compat_vcpu_runstate_info ,
176
+ state_entry_time ));
177
+ #ifdef CONFIG_X86_64
155
178
BUILD_BUG_ON (offsetof(struct vcpu_runstate_info , state_entry_time ) !=
156
179
offsetof(struct compat_vcpu_runstate_info , state_entry_time ) + 4 );
157
180
BUILD_BUG_ON (offsetof(struct vcpu_runstate_info , time ) !=
158
181
offsetof(struct compat_vcpu_runstate_info , time ) + 4 );
159
182
160
183
if (v -> kvm -> arch .xen .long_mode )
161
- offset = offsetof(struct vcpu_runstate_info , state_entry_time );
184
+ user_times = (uint64_t __user * )(ghc -> hva +
185
+ offsetof(struct vcpu_runstate_info ,
186
+ state_entry_time ));
162
187
#endif
163
188
/*
164
189
* First write the updated state_entry_time at the appropriate
@@ -172,10 +197,8 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
172
197
BUILD_BUG_ON (sizeof_field (struct compat_vcpu_runstate_info , state_entry_time ) !=
173
198
sizeof (state_entry_time ));
174
199
175
- if (kvm_write_guest_offset_cached (v -> kvm , & v -> arch .xen .runstate_cache ,
176
- & state_entry_time , offset ,
177
- sizeof (state_entry_time )))
178
- return ;
200
+ if (__put_user (state_entry_time , user_times ))
201
+ goto out ;
179
202
smp_wmb ();
180
203
181
204
/*
@@ -189,11 +212,8 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
189
212
BUILD_BUG_ON (sizeof_field (struct compat_vcpu_runstate_info , state ) !=
190
213
sizeof (vx -> current_runstate ));
191
214
192
- if (kvm_write_guest_offset_cached (v -> kvm , & v -> arch .xen .runstate_cache ,
193
- & vx -> current_runstate ,
194
- offsetof(struct vcpu_runstate_info , state ),
195
- sizeof (vx -> current_runstate )))
196
- return ;
215
+ if (__put_user (vx -> current_runstate , user_state ))
216
+ goto out ;
197
217
198
218
/*
199
219
* Write the actual runstate times immediately after the
@@ -208,24 +228,23 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
208
228
BUILD_BUG_ON (sizeof_field (struct vcpu_runstate_info , time ) !=
209
229
sizeof (vx -> runstate_times ));
210
230
211
- if (kvm_write_guest_offset_cached (v -> kvm , & v -> arch .xen .runstate_cache ,
212
- & vx -> runstate_times [0 ],
213
- offset + sizeof (u64 ),
214
- sizeof (vx -> runstate_times )))
215
- return ;
216
-
231
+ if (__copy_to_user (user_times + 1 , vx -> runstate_times , sizeof (vx -> runstate_times )))
232
+ goto out ;
217
233
smp_wmb ();
218
234
219
235
/*
220
236
* Finally, clear the XEN_RUNSTATE_UPDATE bit in the guest's
221
237
* runstate_entry_time field.
222
238
*/
223
-
224
239
state_entry_time &= ~XEN_RUNSTATE_UPDATE ;
225
- if (kvm_write_guest_offset_cached (v -> kvm , & v -> arch .xen .runstate_cache ,
226
- & state_entry_time , offset ,
227
- sizeof (state_entry_time )))
228
- return ;
240
+ __put_user (state_entry_time , user_times );
241
+ smp_wmb ();
242
+
243
+ out :
244
+ mark_page_dirty_in_slot (v -> kvm , ghc -> memslot , ghc -> gpa >> PAGE_SHIFT );
245
+
246
+ if (atomic )
247
+ pagefault_enable ();
229
248
}
230
249
231
250
int __kvm_xen_has_interrupt (struct kvm_vcpu * v )
@@ -443,6 +462,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
443
462
break ;
444
463
}
445
464
465
+ /* It must fit within a single page */
466
+ if ((data -> u .gpa & ~PAGE_MASK ) + sizeof (struct vcpu_info ) > PAGE_SIZE ) {
467
+ r = - EINVAL ;
468
+ break ;
469
+ }
470
+
446
471
r = kvm_gfn_to_hva_cache_init (vcpu -> kvm ,
447
472
& vcpu -> arch .xen .vcpu_info_cache ,
448
473
data -> u .gpa ,
@@ -460,6 +485,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
460
485
break ;
461
486
}
462
487
488
+ /* It must fit within a single page */
489
+ if ((data -> u .gpa & ~PAGE_MASK ) + sizeof (struct pvclock_vcpu_time_info ) > PAGE_SIZE ) {
490
+ r = - EINVAL ;
491
+ break ;
492
+ }
493
+
463
494
r = kvm_gfn_to_hva_cache_init (vcpu -> kvm ,
464
495
& vcpu -> arch .xen .vcpu_time_info_cache ,
465
496
data -> u .gpa ,
@@ -481,6 +512,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
481
512
break ;
482
513
}
483
514
515
+ /* It must fit within a single page */
516
+ if ((data -> u .gpa & ~PAGE_MASK ) + sizeof (struct vcpu_runstate_info ) > PAGE_SIZE ) {
517
+ r = - EINVAL ;
518
+ break ;
519
+ }
520
+
484
521
r = kvm_gfn_to_hva_cache_init (vcpu -> kvm ,
485
522
& vcpu -> arch .xen .runstate_cache ,
486
523
data -> u .gpa ,
0 commit comments