Commit cc4cb017 authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Paolo Bonzini

KVM: x86: use positive error values for msr emulation that causes #GP

Recent introduction of the userspace msr filtering added code that uses
negative error codes for cases that result in either #GP delivery to
the guest, or handled by the userspace msr filtering.

This breaks an assumption that a negative error code returned from the
msr emulation code is a semi-fatal error which should be returned
to userspace via KVM_RUN ioctl and usually kill the guest.

Fix this by reusing the already existing KVM_MSR_RET_INVALID error code,
and by adding a new KVM_MSR_RET_FILTERED error code for the
userspace filtered msrs.

Fixes: 291f35fb2c1d1 ("KVM: x86: report negative values from wrmsr emulation to userspace")
Reported-by: default avatarQian Cai <cai@redhat.com>
Signed-off-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Message-Id: <20201101115523.115780-1-mlevitsk@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 177158e5
...@@ -255,11 +255,10 @@ static struct kmem_cache *x86_emulator_cache; ...@@ -255,11 +255,10 @@ static struct kmem_cache *x86_emulator_cache;
/* /*
* When called, it means the previous get/set msr reached an invalid msr. * When called, it means the previous get/set msr reached an invalid msr.
* Return 0 if we want to ignore/silent this failed msr access, or 1 if we want * Return true if we want to ignore/silent this failed msr access.
* to fail the caller.
*/ */
static int kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr, static bool kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr,
u64 data, bool write) u64 data, bool write)
{ {
const char *op = write ? "wrmsr" : "rdmsr"; const char *op = write ? "wrmsr" : "rdmsr";
...@@ -268,11 +267,11 @@ static int kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr, ...@@ -268,11 +267,11 @@ static int kvm_msr_ignored_check(struct kvm_vcpu *vcpu, u32 msr,
kvm_pr_unimpl("ignored %s: 0x%x data 0x%llx\n", kvm_pr_unimpl("ignored %s: 0x%x data 0x%llx\n",
op, msr, data); op, msr, data);
/* Mask the error */ /* Mask the error */
return 0; return true;
} else { } else {
kvm_debug_ratelimited("unhandled %s: 0x%x data 0x%llx\n", kvm_debug_ratelimited("unhandled %s: 0x%x data 0x%llx\n",
op, msr, data); op, msr, data);
return -ENOENT; return false;
} }
} }
...@@ -1416,7 +1415,8 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data) ...@@ -1416,7 +1415,8 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
if (r == KVM_MSR_RET_INVALID) { if (r == KVM_MSR_RET_INVALID) {
/* Unconditionally clear the output for simplicity */ /* Unconditionally clear the output for simplicity */
*data = 0; *data = 0;
r = kvm_msr_ignored_check(vcpu, index, 0, false); if (kvm_msr_ignored_check(vcpu, index, 0, false))
r = 0;
} }
if (r) if (r)
...@@ -1540,7 +1540,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, ...@@ -1540,7 +1540,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
struct msr_data msr; struct msr_data msr;
if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE)) if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE))
return -EPERM; return KVM_MSR_RET_FILTERED;
switch (index) { switch (index) {
case MSR_FS_BASE: case MSR_FS_BASE:
...@@ -1581,7 +1581,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu, ...@@ -1581,7 +1581,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu,
int ret = __kvm_set_msr(vcpu, index, data, host_initiated); int ret = __kvm_set_msr(vcpu, index, data, host_initiated);
if (ret == KVM_MSR_RET_INVALID) if (ret == KVM_MSR_RET_INVALID)
ret = kvm_msr_ignored_check(vcpu, index, data, true); if (kvm_msr_ignored_check(vcpu, index, data, true))
ret = 0;
return ret; return ret;
} }
...@@ -1599,7 +1600,7 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, ...@@ -1599,7 +1600,7 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data,
int ret; int ret;
if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ)) if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ))
return -EPERM; return KVM_MSR_RET_FILTERED;
msr.index = index; msr.index = index;
msr.host_initiated = host_initiated; msr.host_initiated = host_initiated;
...@@ -1618,7 +1619,8 @@ static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu, ...@@ -1618,7 +1619,8 @@ static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu,
if (ret == KVM_MSR_RET_INVALID) { if (ret == KVM_MSR_RET_INVALID) {
/* Unconditionally clear *data for simplicity */ /* Unconditionally clear *data for simplicity */
*data = 0; *data = 0;
ret = kvm_msr_ignored_check(vcpu, index, 0, false); if (kvm_msr_ignored_check(vcpu, index, 0, false))
ret = 0;
} }
return ret; return ret;
...@@ -1662,9 +1664,9 @@ static int complete_emulated_wrmsr(struct kvm_vcpu *vcpu) ...@@ -1662,9 +1664,9 @@ static int complete_emulated_wrmsr(struct kvm_vcpu *vcpu)
static u64 kvm_msr_reason(int r) static u64 kvm_msr_reason(int r)
{ {
switch (r) { switch (r) {
case -ENOENT: case KVM_MSR_RET_INVALID:
return KVM_MSR_EXIT_REASON_UNKNOWN; return KVM_MSR_EXIT_REASON_UNKNOWN;
case -EPERM: case KVM_MSR_RET_FILTERED:
return KVM_MSR_EXIT_REASON_FILTER; return KVM_MSR_EXIT_REASON_FILTER;
default: default:
return KVM_MSR_EXIT_REASON_INVAL; return KVM_MSR_EXIT_REASON_INVAL;
......
...@@ -376,7 +376,13 @@ int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r, ...@@ -376,7 +376,13 @@ int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,
int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva); int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva);
bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type); bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type);
#define KVM_MSR_RET_INVALID 2 /*
* Internal error codes that are used to indicate that MSR emulation encountered
* an error that should result in #GP in the guest, unless userspace
* handles it.
*/
#define KVM_MSR_RET_INVALID 2 /* in-kernel MSR emulation #GP condition */
#define KVM_MSR_RET_FILTERED 3 /* #GP due to userspace MSR filter */
#define __cr4_reserved_bits(__cpu_has, __c) \ #define __cr4_reserved_bits(__cpu_has, __c) \
({ \ ({ \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment