aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/common_kvm_amd64_syzos.h29
-rw-r--r--sys/linux/test/amd64-syz_kvm_nested_vmresume-cpuid27
2 files changed, 47 insertions, 9 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h
index 27f4be400..96ff67897 100644
--- a/executor/common_kvm_amd64_syzos.h
+++ b/executor/common_kvm_amd64_syzos.h
@@ -739,6 +739,7 @@ GUEST_CODE static noinline void init_vmcs_control_fields(uint64 cpu_id, uint64 v
typedef enum {
SYZOS_NESTED_EXIT_REASON_HLT = 1,
SYZOS_NESTED_EXIT_REASON_INVD = 2,
+ SYZOS_NESTED_EXIT_REASON_CPUID = 3,
SYZOS_NESTED_EXIT_REASON_UNKNOWN = 0xFF,
} syz_nested_exit_reason;
@@ -754,6 +755,7 @@ GUEST_CODE static void guest_uexit_l2(uint64 exit_reason, syz_nested_exit_reason
}
}
+#define EXIT_REASON_CPUID 0xa
#define EXIT_REASON_HLT 0xc
#define EXIT_REASON_INVD 0xd
@@ -765,15 +767,19 @@ GUEST_CODE static syz_nested_exit_reason map_intel_exit_reason(uint64 basic_reas
return SYZOS_NESTED_EXIT_REASON_HLT;
if (reason == EXIT_REASON_INVD)
return SYZOS_NESTED_EXIT_REASON_INVD;
+ if (reason == EXIT_REASON_CPUID)
+ return SYZOS_NESTED_EXIT_REASON_CPUID;
return SYZOS_NESTED_EXIT_REASON_UNKNOWN;
}
GUEST_CODE static void advance_l2_rip_intel(uint64 basic_reason)
{
- if (basic_reason == EXIT_REASON_INVD) {
- uint64 rip = vmread(VMCS_GUEST_RIP);
- vmwrite(VMCS_GUEST_RIP, rip + 2);
- }
+ // Disable optimizations.
+ volatile uint64 reason = basic_reason;
+ uint64 rip = vmread(VMCS_GUEST_RIP);
+ if ((reason == EXIT_REASON_INVD) || (reason == EXIT_REASON_CPUID))
+ rip += 2;
+ vmwrite(VMCS_GUEST_RIP, rip);
}
// This function is called from inline assembly.
@@ -831,6 +837,7 @@ __attribute__((naked)) GUEST_CODE static void nested_vm_exit_handler_intel_asm(v
[vm_exit_reason] "i"(VMCS_VM_EXIT_REASON) : "memory", "cc", "rbx", "rdi", "rsi");
}
+#define VMEXIT_CPUID 0x72
#define VMEXIT_INVD 0x76
#define VMEXIT_HLT 0x78
@@ -842,16 +849,20 @@ GUEST_CODE static syz_nested_exit_reason map_amd_exit_reason(uint64 basic_reason
return SYZOS_NESTED_EXIT_REASON_HLT;
if (reason == VMEXIT_INVD)
return SYZOS_NESTED_EXIT_REASON_INVD;
+ if (reason == VMEXIT_CPUID)
+ return SYZOS_NESTED_EXIT_REASON_CPUID;
return SYZOS_NESTED_EXIT_REASON_UNKNOWN;
}
GUEST_CODE static void advance_l2_rip_amd(uint64 basic_reason, uint64 cpu_id, uint64 vm_id)
{
- if (basic_reason == VMEXIT_INVD) {
- uint64 vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id);
- uint64 rip = vmcb_read64((volatile uint8*)vmcb_addr, VMCB_GUEST_RIP);
- vmcb_write64(vmcb_addr, VMCB_GUEST_RIP, rip + 2);
- }
+ // Disable optimizations.
+ volatile uint64 reason = basic_reason;
+ uint64 vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id);
+ uint64 rip = vmcb_read64((volatile uint8*)vmcb_addr, VMCB_GUEST_RIP);
+ if ((reason == VMEXIT_INVD) || (reason == VMEXIT_CPUID))
+ rip += 2;
+ vmcb_write64(vmcb_addr, VMCB_GUEST_RIP, rip);
}
__attribute__((used)) GUEST_CODE static void
diff --git a/sys/linux/test/amd64-syz_kvm_nested_vmresume-cpuid b/sys/linux/test/amd64-syz_kvm_nested_vmresume-cpuid
new file mode 100644
index 000000000..43abd7cc3
--- /dev/null
+++ b/sys/linux/test/amd64-syz_kvm_nested_vmresume-cpuid
@@ -0,0 +1,27 @@
+#
+# requires: arch=amd64 -threaded
+#
+r0 = openat$kvm(0, &AUTO='/dev/kvm\x00', 0x0, 0x0)
+r1 = ioctl$KVM_CREATE_VM(r0, AUTO, 0x0)
+r2 = syz_kvm_setup_syzos_vm$x86(r1, &(0x7f0000c00000/0x400000)=nil)
+
+# Create a nested VM that performs CPUID (0f a2) and HLT (f4).
+#
+r3 = syz_kvm_add_vcpu$x86(r2, &AUTO={0x0, &AUTO=[@enable_nested={AUTO, AUTO, 0x0}, @nested_create_vm={AUTO, AUTO, 0x0}, @nested_load_code={AUTO, AUTO, {0x0, "0fa2f4"}}, @nested_vmlaunch={AUTO, AUTO, 0x0}, @nested_vmresume={AUTO, AUTO, 0x0}], AUTO})
+r4 = ioctl$KVM_GET_VCPU_MMAP_SIZE(r0, AUTO)
+r5 = mmap$KVM_VCPU(&(0x7f0000009000/0x1000)=nil, r4, 0x3, 0x1, r3, 0x0)
+
+# L2 VM executes CPUID. Exit reason is mapped to 0xe2e20003.
+#
+ioctl$KVM_RUN(r3, AUTO, 0x0)
+syz_kvm_assert_syzos_uexit$x86(r5, 0xe2e20003)
+
+# L1 resumes L2, which executes HLT. Exit reason is mapped to 0xe2e20001.
+#
+ioctl$KVM_RUN(r3, AUTO, 0x0)
+syz_kvm_assert_syzos_uexit$x86(r5, 0xe2e20001)
+
+# guest_main should finish with guest_uexit(-1).
+#
+ioctl$KVM_RUN(r3, AUTO, 0x0)
+syz_kvm_assert_syzos_uexit$x86(r5, 0xffffffff)