When DecodeAssists is exposed to L1, copy fresh hardware instruction bytes from VMCB02 to VMCB12 for data #NPF and intercepted #PF VM-Exits. Clear VMCB12's instruction-byte state for instruction-fetch faults, unrelated exits, and exits without fresh VMCB02 state so that stale bytes are not exposed to L1. Signed-off-by: Tina Zhang --- arch/x86/kvm/svm/nested.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 70e2ee3af78b..9e12eab7eed9 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -40,6 +40,57 @@ static void nested_svm_clear_insn_bytes(struct vmcb *vmcb) sizeof(vmcb->control.insn_bytes)); } +static void nested_svm_copy_insn_bytes(struct vmcb *to, + const struct vmcb *from) +{ + u8 insn_len = from->control.insn_len; + + nested_svm_clear_insn_bytes(to); + + if (WARN_ON_ONCE(insn_len > sizeof(from->control.insn_bytes))) + return; + + to->control.insn_len = insn_len; + memcpy(to->control.insn_bytes, from->control.insn_bytes, insn_len); +} + +static bool nested_svm_vmexit_supports_insn_bytes(struct kvm_vcpu *vcpu, + const struct vmcb *vmcb12) +{ + u64 exit_code = vmcb12->control.exit_code; + + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_DECODEASSISTS)) + return false; + + if (exit_code != SVM_EXIT_NPF && + exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) + return false; + + return !(vmcb12->control.exit_info_1 & PFERR_FETCH_MASK); +} + +/* + * Rebuild VMCB12's DecodeAssist bytes for the nested VM-Exit. Use fresh + * hardware VMCB02 state when available; otherwise report a zero byte count. + */ +static void nested_svm_update_vmcb12_insn_bytes(struct kvm_vcpu *vcpu, + struct vmcb *vmcb12, + struct vmcb *vmcb02) +{ + struct vcpu_svm *svm = to_svm(vcpu); + bool vmcb02_insn_bytes_fresh = svm->nested.vmcb02_insn_bytes_fresh; + + svm->nested.vmcb02_insn_bytes_fresh = false; + + nested_svm_clear_insn_bytes(vmcb12); + + if (!nested_svm_vmexit_supports_insn_bytes(vcpu, vmcb12)) + return; + + if (vmcb02_insn_bytes_fresh) + nested_svm_copy_insn_bytes(vmcb12, vmcb02); +} + static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu, struct x86_exception *fault) { @@ -1263,6 +1314,8 @@ static int nested_svm_vmexit_update_vmcb12(struct kvm_vcpu *vcpu) if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS)) vmcb12->control.next_rip = vmcb02->control.next_rip; + nested_svm_update_vmcb12_insn_bytes(vcpu, vmcb12, vmcb02); + if (nested_vmcb12_has_lbrv(vcpu)) svm_copy_lbrs(&vmcb12->save, &vmcb02->save); -- 2.43.7