Skip to content

Commit d97c066

Browse files
sean-jcgregkh
authored andcommitted
KVM: x86: Use __try_cmpxchg_user() to emulate atomic accesses
[ Upstream commit 1c2361f ] Use the recently introduce __try_cmpxchg_user() to emulate atomic guest accesses via the associated userspace address instead of mapping the backing pfn into kernel address space. Using kvm_vcpu_map() is unsafe as it does not coordinate with KVM's mmu_notifier to ensure the hva=>pfn translation isn't changed/unmapped in the memremap() path, i.e. when there's no struct page and thus no elevated refcount. Fixes: 42e35f8 ("KVM/X86: Use kvm_vcpu_map in emulator_cmpxchg_emulated") Cc: [email protected] Signed-off-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 88eded8 commit d97c066

File tree

1 file changed

+14
-21
lines changed

1 file changed

+14
-21
lines changed

arch/x86/kvm/x86.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6894,15 +6894,8 @@ static int emulator_write_emulated(struct x86_emulate_ctxt *ctxt,
68946894
exception, &write_emultor);
68956895
}
68966896

6897-
#define CMPXCHG_TYPE(t, ptr, old, new) \
6898-
(cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))
6899-
6900-
#ifdef CONFIG_X86_64
6901-
# define CMPXCHG64(ptr, old, new) CMPXCHG_TYPE(u64, ptr, old, new)
6902-
#else
6903-
# define CMPXCHG64(ptr, old, new) \
6904-
(cmpxchg64((u64 *)(ptr), *(u64 *)(old), *(u64 *)(new)) == *(u64 *)(old))
6905-
#endif
6897+
#define emulator_try_cmpxchg_user(t, ptr, old, new) \
6898+
(__try_cmpxchg_user((t __user *)(ptr), (t *)(old), *(t *)(new), efault ## t))
69066899

69076900
static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
69086901
unsigned long addr,
@@ -6911,12 +6904,11 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
69116904
unsigned int bytes,
69126905
struct x86_exception *exception)
69136906
{
6914-
struct kvm_host_map map;
69156907
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
69166908
u64 page_line_mask;
6909+
unsigned long hva;
69176910
gpa_t gpa;
6918-
char *kaddr;
6919-
bool exchanged;
6911+
int r;
69206912

69216913
/* guests cmpxchg8b have to be emulated atomically */
69226914
if (bytes > 8 || (bytes & (bytes - 1)))
@@ -6940,31 +6932,32 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
69406932
if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask))
69416933
goto emul_write;
69426934

6943-
if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), &map))
6935+
hva = kvm_vcpu_gfn_to_hva(vcpu, gpa_to_gfn(gpa));
6936+
if (kvm_is_error_hva(addr))
69446937
goto emul_write;
69456938

6946-
kaddr = map.hva + offset_in_page(gpa);
6939+
hva += offset_in_page(gpa);
69476940

69486941
switch (bytes) {
69496942
case 1:
6950-
exchanged = CMPXCHG_TYPE(u8, kaddr, old, new);
6943+
r = emulator_try_cmpxchg_user(u8, hva, old, new);
69516944
break;
69526945
case 2:
6953-
exchanged = CMPXCHG_TYPE(u16, kaddr, old, new);
6946+
r = emulator_try_cmpxchg_user(u16, hva, old, new);
69546947
break;
69556948
case 4:
6956-
exchanged = CMPXCHG_TYPE(u32, kaddr, old, new);
6949+
r = emulator_try_cmpxchg_user(u32, hva, old, new);
69576950
break;
69586951
case 8:
6959-
exchanged = CMPXCHG64(kaddr, old, new);
6952+
r = emulator_try_cmpxchg_user(u64, hva, old, new);
69606953
break;
69616954
default:
69626955
BUG();
69636956
}
69646957

6965-
kvm_vcpu_unmap(vcpu, &map, true);
6966-
6967-
if (!exchanged)
6958+
if (r < 0)
6959+
goto emul_write;
6960+
if (r)
69686961
return X86EMUL_CMPXCHG_FAILED;
69696962

69706963
kvm_page_track_write(vcpu, gpa, new, bytes);

0 commit comments

Comments
 (0)