Skip to content

Commit 16fe7d5

Browse files
executor: sys/linux: SYZOS: add AMD VMLOAD and VMSAVE primitives
This patch introduces SYZOS_API_NESTED_AMD_VMLOAD and SYZOS_API_NESTED_AMD_VMSAVE. These primitives allow the L1 guest to execute the VMLOAD and VMSAVE instructions, which load/store additional guest state (FS, GS, TR, LDTR, etc.) to/from the VMCB specified by the 'vm_id' argument. This stresses the KVM L0 instruction emulator, which must validate the L1-provided physical address in RAX and perform the state transfer.
1 parent 06648d9 commit 16fe7d5

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

executor/common_kvm_amd64_syzos.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef enum {
3838
SYZOS_API_NESTED_AMD_CLGI = 383,
3939
SYZOS_API_NESTED_AMD_INJECT_EVENT = 384,
4040
SYZOS_API_NESTED_AMD_SET_INTERCEPT = 385,
41+
SYZOS_API_NESTED_AMD_VMLOAD = 386,
42+
SYZOS_API_NESTED_AMD_VMSAVE = 387,
4143
SYZOS_API_STOP, // Must be the last one
4244
} syzos_api_id;
4345

@@ -123,6 +125,8 @@ GUEST_CODE static void guest_handle_nested_amd_stgi();
123125
GUEST_CODE static void guest_handle_nested_amd_clgi();
124126
GUEST_CODE static void guest_handle_nested_amd_inject_event(struct api_call_5* cmd, uint64 cpu_id);
125127
GUEST_CODE static void guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id);
128+
GUEST_CODE static void guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id);
129+
GUEST_CODE static void guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id);
126130

127131
typedef enum {
128132
UEXIT_END = (uint64)-1,
@@ -253,6 +257,12 @@ guest_main(uint64 size, uint64 cpu)
253257
} else if (call == SYZOS_API_NESTED_AMD_SET_INTERCEPT) {
254258
// Set/Clear specific intercept bits in the VMCB.
255259
guest_handle_nested_amd_set_intercept((struct api_call_5*)cmd, cpu);
260+
} else if (call == SYZOS_API_NESTED_AMD_VMLOAD) {
261+
// Execute VMLOAD to load state from VMCB.
262+
guest_handle_nested_amd_vmload((struct api_call_1*)cmd, cpu);
263+
} else if (call == SYZOS_API_NESTED_AMD_VMSAVE) {
264+
// Execute VMSAVE to save state to VMCB.
265+
guest_handle_nested_amd_vmsave((struct api_call_1*)cmd, cpu);
256266
}
257267
addr += cmd->size;
258268
size -= cmd->size;
@@ -1392,4 +1402,26 @@ guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id)
13921402
vmcb_write32(vmcb_addr, (uint16)offset, current);
13931403
}
13941404

1405+
GUEST_CODE static noinline void
1406+
guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id)
1407+
{
1408+
if (get_cpu_vendor() != CPU_VENDOR_AMD)
1409+
return;
1410+
uint64 vm_id = cmd->arg;
1411+
uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id);
1412+
1413+
asm volatile("vmload %%rax" :: "a"(vmcb_pa) : "memory");
1414+
}
1415+
1416+
GUEST_CODE static noinline void
1417+
guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id)
1418+
{
1419+
if (get_cpu_vendor() != CPU_VENDOR_AMD)
1420+
return;
1421+
uint64 vm_id = cmd->arg;
1422+
uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id);
1423+
1424+
asm volatile("vmsave %%rax" :: "a"(vmcb_pa) : "memory");
1425+
}
1426+
13951427
#endif // EXECUTOR_COMMON_KVM_AMD64_SYZOS_H

sys/linux/dev_kvm_amd64.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ syzos_api_call$x86 [
191191
nested_amd_clgi syzos_api$x86[383, void]
192192
nested_amd_inject_event syzos_api$x86[384, syzos_api_nested_amd_inject_event]
193193
nested_amd_set_intercept syzos_api$x86[385, syzos_api_nested_amd_set_intercept]
194+
nested_amd_vmload syzos_api$x86[386, syzos_api_vm_id]
195+
nested_amd_vmsave syzos_api$x86[387, syzos_api_vm_id]
194196
] [varlen]
195197

196198
kvm_text_x86 [
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# requires: arch=amd64 -threaded
3+
#
4+
5+
# VMLOAD/VMSAVE Reproducer
6+
#
7+
r0 = openat$kvm(0xffffffffffffff9c, &AUTO='/dev/kvm\x00', 0x0, 0x0)
8+
r1 = ioctl$KVM_CREATE_VM(r0, 0x0, 0x0)
9+
r2 = syz_kvm_setup_syzos_vm$x86(r1, &(0x7f0000000000/0x400000)=nil)
10+
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})
11+
ioctl$KVM_RUN(r3, 0x0, 0x0)

0 commit comments

Comments
 (0)