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: Qian Cai <cai@redhat.com> Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Message-Id: <20201101115523.115780-1-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
177158e5b1
commit
cc4cb01767
@ -255,10 +255,9 @@ 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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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) \
|
||||||
({ \
|
({ \
|
||||||
|
Loading…
Reference in New Issue
Block a user