KVM: VMX: Fix ds/es corruption on i386 with preemption

Commit b2da15ac26a0c ("KVM: VMX: Optimize %ds, %es reload") broke i386
in the following scenario:

vcpu_load
...
vmx_save_host_state
vmx_vcpu_run
(ds.rpl, es.rpl cleared by hardware)

interrupt
push ds, es # pushes bad ds, es
schedule
vmx_vcpu_put
vmx_load_host_state
reload ds, es (with __USER_DS)
pop ds, es # of other thread's stack
iret
# other thread runs
interrupt
push ds, es
schedule # back in vcpu thread
pop ds, es # now with rpl=0
iret
...
vcpu_put
resume_userspace
iret # clears ds, es due to mismatched rpl

(instead of resume_userspace, we might return with SYSEXIT and then
take an exception; when the exception IRETs we end up with cleared
ds, es)

Fix by avoiding the optimization on i386 and reloading ds, es on the
lightweight exit path.

Reported-by: Chris Clayron <chris2553@googlemail.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>

authored by Avi Kivity and committed by Marcelo Tosatti aa67f609 4b648665

Changed files
+13 -7
arch
x86
kvm
+13 -7
arch/x86/kvm/vmx.c
··· 1488 loadsegment(ds, vmx->host_state.ds_sel); 1489 loadsegment(es, vmx->host_state.es_sel); 1490 } 1491 - #else 1492 - /* 1493 - * The sysexit path does not restore ds/es, so we must set them to 1494 - * a reasonable value ourselves. 1495 - */ 1496 - loadsegment(ds, __USER_DS); 1497 - loadsegment(es, __USER_DS); 1498 #endif 1499 reload_tss(); 1500 #ifdef CONFIG_X86_64 ··· 6362 , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 6363 #endif 6364 ); 6365 6366 vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) 6367 | (1 << VCPU_EXREG_RFLAGS)
··· 1488 loadsegment(ds, vmx->host_state.ds_sel); 1489 loadsegment(es, vmx->host_state.es_sel); 1490 } 1491 #endif 1492 reload_tss(); 1493 #ifdef CONFIG_X86_64 ··· 6369 , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 6370 #endif 6371 ); 6372 + 6373 + #ifndef CONFIG_X86_64 6374 + /* 6375 + * The sysexit path does not restore ds/es, so we must set them to 6376 + * a reasonable value ourselves. 6377 + * 6378 + * We can't defer this to vmx_load_host_state() since that function 6379 + * may be executed in interrupt context, which saves and restore segments 6380 + * around it, nullifying its effect. 6381 + */ 6382 + loadsegment(ds, __USER_DS); 6383 + loadsegment(es, __USER_DS); 6384 + #endif 6385 6386 vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) 6387 | (1 << VCPU_EXREG_RFLAGS)