Skip to content

Commit 04c40f3

Browse files
sean-jcbonzini
authored andcommitted
KVM: SVM: Inject #UD on attempted emulation for SEV guest w/o insn buffer
Inject #UD if KVM attempts emulation for an SEV guests without an insn buffer and instruction decoding is required. The previous behavior of allowing emulation if there is no insn buffer is undesirable as doing so means KVM is reading guest private memory and thus decoding cyphertext, i.e. is emulating garbage. The check was previously necessary as the emulation type was not provided, i.e. SVM needed to allow emulation to handle completion of emulation after exiting to userspace to handle I/O. Signed-off-by: Sean Christopherson <[email protected]> Reviewed-by: Liam Merwick <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 132627c commit 04c40f3

File tree

1 file changed

+55
-34
lines changed

1 file changed

+55
-34
lines changed

arch/x86/kvm/svm/svm.c

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4280,49 +4280,70 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
42804280
if (sev_es_guest(vcpu->kvm))
42814281
return false;
42824282

4283+
/*
4284+
* Emulation is possible if the instruction is already decoded, e.g.
4285+
* when completing I/O after returning from userspace.
4286+
*/
4287+
if (emul_type & EMULTYPE_NO_DECODE)
4288+
return true;
4289+
4290+
/*
4291+
* Emulation is possible for SEV guests if and only if a prefilled
4292+
* buffer containing the bytes of the intercepted instruction is
4293+
* available. SEV guest memory is encrypted with a guest specific key
4294+
* and cannot be decrypted by KVM, i.e. KVM would read cyphertext and
4295+
* decode garbage.
4296+
*
4297+
* Inject #UD if KVM reached this point without an instruction buffer.
4298+
* In practice, this path should never be hit by a well-behaved guest,
4299+
* e.g. KVM doesn't intercept #UD or #GP for SEV guests, but this path
4300+
* is still theoretically reachable, e.g. via unaccelerated fault-like
4301+
* AVIC access, and needs to be handled by KVM to avoid putting the
4302+
* guest into an infinite loop. Injecting #UD is somewhat arbitrary,
4303+
* but its the least awful option given lack of insight into the guest.
4304+
*/
4305+
if (unlikely(!insn)) {
4306+
kvm_queue_exception(vcpu, UD_VECTOR);
4307+
return false;
4308+
}
4309+
4310+
/*
4311+
* Emulate for SEV guests if the insn buffer is not empty. The buffer
4312+
* will be empty if the DecodeAssist microcode cannot fetch bytes for
4313+
* the faulting instruction because the code fetch itself faulted, e.g.
4314+
* the guest attempted to fetch from emulated MMIO or a guest page
4315+
* table used to translate CS:RIP resides in emulated MMIO.
4316+
*/
4317+
if (likely(insn_len))
4318+
return true;
4319+
42834320
/*
42844321
* Detect and workaround Errata 1096 Fam_17h_00_0Fh.
42854322
*
42864323
* Errata:
4287-
* When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is
4288-
* possible that CPU microcode implementing DecodeAssist will fail
4289-
* to read bytes of instruction which caused #NPF. In this case,
4290-
* GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly
4291-
* return 0 instead of the correct guest instruction bytes.
4292-
*
4293-
* This happens because CPU microcode reading instruction bytes
4294-
* uses a special opcode which attempts to read data using CPL=0
4295-
* privileges. The microcode reads CS:RIP and if it hits a SMAP
4296-
* fault, it gives up and returns no instruction bytes.
4324+
* When CPU raises #NPF on guest data access and vCPU CR4.SMAP=1, it is
4325+
* possible that CPU microcode implementing DecodeAssist will fail to
4326+
* read guest memory at CS:RIP and vmcb.GuestIntrBytes will incorrectly
4327+
* be '0'. This happens because microcode reads CS:RIP using a _data_
4328+
* loap uop with CPL=0 privileges. If the load hits a SMAP #PF, ucode
4329+
* gives up and does not fill the instruction bytes buffer.
42974330
*
42984331
* Detection:
4299-
* We reach here in case CPU supports DecodeAssist, raised #NPF and
4300-
* returned 0 in GuestIntrBytes field of the VMCB.
4301-
* First, errata can only be triggered in case vCPU CR4.SMAP=1.
4302-
* Second, if vCPU CR4.SMEP=1, errata could only be triggered
4303-
* in case vCPU CPL==3 (Because otherwise guest would have triggered
4304-
* a SMEP fault instead of #NPF).
4305-
* Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL.
4306-
* As most guests enable SMAP if they have also enabled SMEP, use above
4307-
* logic in order to attempt minimize false-positive of detecting errata
4308-
* while still preserving all cases semantic correctness.
4309-
*
4310-
* Workaround:
4311-
* To determine what instruction the guest was executing, the hypervisor
4312-
* will have to decode the instruction at the instruction pointer.
4332+
* KVM reaches this point if the VM is an SEV guest, the CPU supports
4333+
* DecodeAssist, a #NPF was raised, KVM's page fault handler triggered
4334+
* emulation (e.g. for MMIO), and the CPU returned 0 in GuestIntrBytes
4335+
* field of the VMCB.
43134336
*
4314-
* In non SEV guest, hypervisor will be able to read the guest
4315-
* memory to decode the instruction pointer when insn_len is zero
4316-
* so we return true to indicate that decoding is possible.
4337+
* This does _not_ mean that the erratum has been encountered, as the
4338+
* DecodeAssist will also fail if the load for CS:RIP hits a legitimate
4339+
* #PF, e.g. if the guest attempt to execute from emulated MMIO and
4340+
* encountered a reserved/not-present #PF.
43174341
*
4318-
* But in the SEV guest, the guest memory is encrypted with the
4319-
* guest specific key and hypervisor will not be able to decode the
4320-
* instruction pointer so we will not able to workaround it. Lets
4321-
* print the error and request to kill the guest.
4342+
* To reduce the likelihood of false positives, take action if and only
4343+
* if CR4.SMAP=1 (obviously required to hit the erratum) and CR4.SMEP=0
4344+
* or CPL=3. If SMEP=1 and CPL!=3, the erratum cannot have been hit as
4345+
* the guest would have encountered a SMEP violation #PF, not a #NPF.
43224346
*/
4323-
if (likely(!insn || insn_len))
4324-
return true;
4325-
43264347
cr4 = kvm_read_cr4(vcpu);
43274348
smep = cr4 & X86_CR4_SMEP;
43284349
smap = cr4 & X86_CR4_SMAP;

0 commit comments

Comments
 (0)