Skip to content

Commit fd30841

Browse files
committed
KVM: x86: avoid calling x86 emulator without a decoded instruction
jira VULN-3154 cve CVE-2022-1852 commit-author Sean Christopherson <seanjc@google.com> commit fee060c Whenever x86_decode_emulated_instruction() detects a breakpoint, it returns the value that kvm_vcpu_check_breakpoint() writes into its pass-by-reference second argument. Unfortunately this is completely bogus because the expected outcome of x86_decode_emulated_instruction is an EMULATION_* value. Then, if kvm_vcpu_check_breakpoint() does "*r = 0" (corresponding to a KVM_EXIT_DEBUG userspace exit), it is misunderstood as EMULATION_OK and x86_emulate_instruction() is called without having decoded the instruction. This causes various havoc from running with a stale emulation context. The fix is to move the call to kvm_vcpu_check_breakpoint() where it was before commit 4aa2691 ("KVM: x86: Factor out x86 instruction emulation with decoding") introduced x86_decode_emulated_instruction(). The other caller of the function does not need breakpoint checks, because it is invoked as part of a vmexit and the processor has already checked those before executing the instruction that #GP'd. This fixes CVE-2022-1852. Reported-by: Qiuhao Li <qiuhao@sysec.org> Reported-by: Gaoning Pan <pgn@zju.edu.cn> Reported-by: Yongkang Jia <kangel@zju.edu.cn> Fixes: 4aa2691 ("KVM: x86: Factor out x86 instruction emulation with decoding") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20220311032801.3467418-2-seanjc@google.com> [Rewrote commit message according to Qiuhao's report, since a patch already existed to fix the bug. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> (cherry picked from commit fee060c) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent bd80602 commit fd30841

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

arch/x86/kvm/x86.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7973,7 +7973,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu)
79737973
}
79747974
EXPORT_SYMBOL_GPL(kvm_skip_emulated_instruction);
79757975

7976-
static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
7976+
static bool kvm_vcpu_check_code_breakpoint(struct kvm_vcpu *vcpu, int *r)
79777977
{
79787978
if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) &&
79797979
(vcpu->arch.guest_debug_dr7 & DR7_BP_EN_MASK)) {
@@ -8042,25 +8042,23 @@ static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)
80428042
}
80438043

80448044
/*
8045-
* Decode to be emulated instruction. Return EMULATION_OK if success.
8045+
* Decode an instruction for emulation. The caller is responsible for handling
8046+
* code breakpoints. Note, manually detecting code breakpoints is unnecessary
8047+
* (and wrong) when emulating on an intercepted fault-like exception[*], as
8048+
* code breakpoints have higher priority and thus have already been done by
8049+
* hardware.
8050+
*
8051+
* [*] Except #MC, which is higher priority, but KVM should never emulate in
8052+
* response to a machine check.
80468053
*/
80478054
int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type,
80488055
void *insn, int insn_len)
80498056
{
8050-
int r = EMULATION_OK;
80518057
struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
8058+
int r;
80528059

80538060
init_emulate_ctxt(vcpu);
80548061

8055-
/*
8056-
* We will reenter on the same instruction since we do not set
8057-
* complete_userspace_io. This does not handle watchpoints yet,
8058-
* those would be handled in the emulate_ops.
8059-
*/
8060-
if (!(emulation_type & EMULTYPE_SKIP) &&
8061-
kvm_vcpu_check_breakpoint(vcpu, &r))
8062-
return r;
8063-
80648062
r = x86_decode_insn(ctxt, insn, insn_len, emulation_type);
80658063

80668064
trace_kvm_emulate_insn_start(vcpu);
@@ -8093,6 +8091,15 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
80938091
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
80948092
kvm_clear_exception_queue(vcpu);
80958093

8094+
/*
8095+
* Return immediately if RIP hits a code breakpoint, such #DBs
8096+
* are fault-like and are higher priority than any faults on
8097+
* the code fetch itself.
8098+
*/
8099+
if (!(emulation_type & EMULTYPE_SKIP) &&
8100+
kvm_vcpu_check_code_breakpoint(vcpu, &r))
8101+
return r;
8102+
80968103
r = x86_decode_emulated_instruction(vcpu, emulation_type,
80978104
insn, insn_len);
80988105
if (r != EMULATION_OK) {

0 commit comments

Comments
 (0)