On Sat, Jul 28, 2018 at 4:10 PM, Paolo Bonzini <pbonzini@xxxxxxxxxx> wrote: > The shadow vmcs12 cannot be flushed on KVM_GET_NESTED_STATE, > because at that point guest memory is assumed by userspace to > be immutable. Capture the cache in vmx_get_nested_state, adding > another page at the end if there is an active shadow vmcs12. > > Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> > --- > arch/x86/kvm/vmx.c | 31 ++++++++++++++++++++++++++++++- > 1 file changed, 30 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c > index b5ee9e08bb48..ce8c0c759a19 100644 > --- a/arch/x86/kvm/vmx.c > +++ b/arch/x86/kvm/vmx.c > @@ -13167,9 +13167,15 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, > kvm_state.vmx.vmxon_pa = vmx->nested.vmxon_ptr; > kvm_state.vmx.vmcs_pa = vmx->nested.current_vmptr; > > - if (vmx->nested.current_vmptr != -1ull) > + if (vmx->nested.current_vmptr != -1ull) { > kvm_state.size += VMCS12_SIZE; > > + if (is_guest_mode(vcpu) && > + nested_cpu_has_shadow_vmcs(vmcs12) && > + vmcs12->vmcs_link_pointer != -1ull) > + kvm_state.size += VMCS12_SIZE; > + } > + > if (vmx->nested.smm.vmxon) > kvm_state.vmx.smm.flags |= KVM_STATE_NESTED_SMM_VMXON; > > @@ -13208,6 +13214,13 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, > if (copy_to_user(user_kvm_nested_state->data, vmcs12, sizeof(*vmcs12))) > return -EFAULT; > > + if (nested_cpu_has_shadow_vmcs(vmcs12) && > + vmcs12->vmcs_link_pointer != -1ull) { > + if (copy_to_user(user_kvm_nested_state->data + VMCS12_SIZE, > + get_shadow_vmcs12(vcpu), sizeof(*vmcs12))) Does this work with CONFIG_HARDENED_USERCOPY? Is VMCS12_SIZE better than sizeof(*vmcs12)? What if we are migrating to a destination where sizeof(*vmcs12) is larger than it is on the source? If userspace doesn't zero the buffer before calling the ioctl, then the destination may interpret nonsense as actual VMCS field values. However, if we copy the entire page from the kernel, then we know that anything beyond the source's sizeof(*vmcs12) will be zero. > + return -EFAULT; > + } > + > out: > return kvm_state.size; > } > @@ -13288,6 +13301,22 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, > vmx->nested.nested_run_pending = > !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING); > > + if (nested_cpu_has_shadow_vmcs(vmcs12) && > + vmcs12->vmcs_link_pointer != -1ull) { > + struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu); > + if (kvm_state->size < sizeof(kvm_state) + 2 * sizeof(*vmcs12)) > + return -EINVAL; > + > + if (copy_from_user(shadow_vmcs12, > + user_kvm_nested_state->data + VMCS12_SIZE, > + sizeof(*vmcs12))) > + return -EFAULT; > + > + if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION || > + !shadow_vmcs12->hdr.shadow_vmcs) > + return -EINVAL; > + } > + > if (check_vmentry_prereqs(vcpu, vmcs12) || > check_vmentry_postreqs(vcpu, vmcs12, &exit_qual)) > return -EINVAL; > -- > 1.8.3.1 >