diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h index 31f62a79cdd1..5584a62b99c4 100644 --- a/executor/common_kvm_amd64_syzos.h +++ b/executor/common_kvm_amd64_syzos.h @@ -38,6 +38,8 @@ typedef enum { SYZOS_API_NESTED_AMD_CLGI = 383, SYZOS_API_NESTED_AMD_INJECT_EVENT = 384, SYZOS_API_NESTED_AMD_SET_INTERCEPT = 385, + SYZOS_API_NESTED_AMD_VMLOAD = 386, + SYZOS_API_NESTED_AMD_VMSAVE = 387, SYZOS_API_STOP, // Must be the last one } syzos_api_id; @@ -123,6 +125,8 @@ GUEST_CODE static void guest_handle_nested_amd_stgi(); GUEST_CODE static void guest_handle_nested_amd_clgi(); GUEST_CODE static void guest_handle_nested_amd_inject_event(struct api_call_5* cmd, uint64 cpu_id); GUEST_CODE static void guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id); +GUEST_CODE static void guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id); +GUEST_CODE static void guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id); typedef enum { UEXIT_END = (uint64)-1, @@ -253,6 +257,12 @@ guest_main(uint64 size, uint64 cpu) } else if (call == SYZOS_API_NESTED_AMD_SET_INTERCEPT) { // Set/Clear specific intercept bits in the VMCB. guest_handle_nested_amd_set_intercept((struct api_call_5*)cmd, cpu); + } else if (call == SYZOS_API_NESTED_AMD_VMLOAD) { + // Execute VMLOAD to load state from VMCB. + guest_handle_nested_amd_vmload((struct api_call_1*)cmd, cpu); + } else if (call == SYZOS_API_NESTED_AMD_VMSAVE) { + // Execute VMSAVE to save state to VMCB. + guest_handle_nested_amd_vmsave((struct api_call_1*)cmd, cpu); } addr += cmd->size; size -= cmd->size; @@ -1392,4 +1402,26 @@ guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id) vmcb_write32(vmcb_addr, (uint16)offset, current); } +GUEST_CODE static noinline void +guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id) +{ + if (get_cpu_vendor() != CPU_VENDOR_AMD) + return; + uint64 vm_id = cmd->arg; + uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); + + asm volatile("vmload %%rax" ::"a"(vmcb_pa) : "memory"); +} + +GUEST_CODE static noinline void +guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id) +{ + if (get_cpu_vendor() != CPU_VENDOR_AMD) + return; + uint64 vm_id = cmd->arg; + uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); + + asm volatile("vmsave %%rax" ::"a"(vmcb_pa) : "memory"); +} + #endif // EXECUTOR_COMMON_KVM_AMD64_SYZOS_H diff --git a/sys/linux/dev_kvm_amd64.txt b/sys/linux/dev_kvm_amd64.txt index 0d90ceeab9fb..4694f93ccfa2 100644 --- a/sys/linux/dev_kvm_amd64.txt +++ b/sys/linux/dev_kvm_amd64.txt @@ -191,6 +191,8 @@ syzos_api_call$x86 [ nested_amd_clgi syzos_api$x86[383, void] nested_amd_inject_event syzos_api$x86[384, syzos_api_nested_amd_inject_event] nested_amd_set_intercept syzos_api$x86[385, syzos_api_nested_amd_set_intercept] + nested_amd_vmload syzos_api$x86[386, syzos_api_vm_id] + nested_amd_vmsave syzos_api$x86[387, syzos_api_vm_id] ] [varlen] kvm_text_x86 [ diff --git a/sys/linux/test/amd64-syz_kvm_nested_vmload_vmsave b/sys/linux/test/amd64-syz_kvm_nested_vmload_vmsave new file mode 100644 index 000000000000..c8e169f6190d --- /dev/null +++ b/sys/linux/test/amd64-syz_kvm_nested_vmload_vmsave @@ -0,0 +1,11 @@ +# +# requires: arch=amd64 -threaded +# + +# VMLOAD/VMSAVE Reproducer +# +r0 = openat$kvm(0xffffffffffffff9c, &AUTO='/dev/kvm\x00', 0x0, 0x0) +r1 = ioctl$KVM_CREATE_VM(r0, 0x0, 0x0) +r2 = syz_kvm_setup_syzos_vm$x86(r1, &(0x7f0000000000/0x400000)=nil) +r3 = syz_kvm_add_vcpu$x86(r2, &AUTO={0x0, &AUTO=[@enable_nested={0x12c, 0x18, 0x0}, @nested_create_vm={0x12d, 0x18, 0x1}, @nested_amd_vmsave={0x183, 0x18, 0x1}, @nested_amd_vmload={0x182, 0x18, 0x1}], 0x0}) +ioctl$KVM_RUN(r3, 0x0, 0x0)