aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2025-11-18 12:07:13 +0100
committerAlexander Potapenko <glider@google.com>2025-11-19 08:59:40 +0000
commit5af4be3c78a6a9fc6a3c9c3d1a48151f190c9221 (patch)
treeffc583dc53550376e34eb33fceafad7b74076cf6 /executor
parent3bf489934f218dfcb171b6db6db3ecce818971db (diff)
executor: sys/linux: implement SYZOS_API_NESTED_LOAD_CODE
The new command loads an instruction blob into the specified L2 VM.
Diffstat (limited to 'executor')
-rw-r--r--executor/common_kvm_amd64_syzos.h41
1 files changed, 41 insertions, 0 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h
index 9f93af017..739868440 100644
--- a/executor/common_kvm_amd64_syzos.h
+++ b/executor/common_kvm_amd64_syzos.h
@@ -28,6 +28,7 @@ typedef enum {
SYZOS_API_SET_IRQ_HANDLER = 200,
SYZOS_API_ENABLE_NESTED = 300,
SYZOS_API_NESTED_CREATE_VM = 301,
+ SYZOS_API_NESTED_LOAD_CODE = 302,
SYZOS_API_STOP, // Must be the last one
} syzos_api_id;
@@ -46,6 +47,12 @@ struct api_call_code {
uint8 insns[];
};
+struct api_call_nested_load_code {
+ struct api_call_header header;
+ uint64 vm_id;
+ uint8 insns[];
+};
+
struct api_call_cpuid {
struct api_call_header header;
uint32 eax;
@@ -85,6 +92,7 @@ GUEST_CODE static void guest_handle_out_dx(struct api_call_3* cmd);
GUEST_CODE static void guest_handle_set_irq_handler(struct api_call_2* cmd);
GUEST_CODE static void guest_handle_enable_nested(struct api_call_1* cmd, uint64 cpu_id);
GUEST_CODE static void guest_handle_nested_create_vm(struct api_call_1* cmd, uint64 cpu_id);
+GUEST_CODE static void guest_handle_nested_load_code(struct api_call_nested_load_code* cmd, uint64 cpu_id);
typedef enum {
UEXIT_END = (uint64)-1,
@@ -185,6 +193,9 @@ guest_main(uint64 size, uint64 cpu)
} else if (call == SYZOS_API_NESTED_CREATE_VM) {
// Create a nested VM.
guest_handle_nested_create_vm((struct api_call_1*)cmd, cpu);
+ } else if (call == SYZOS_API_NESTED_LOAD_CODE) {
+ // Load code into the nested VM.
+ guest_handle_nested_load_code((struct api_call_nested_load_code*)cmd, cpu);
}
addr += cmd->size;
size -= cmd->size;
@@ -534,6 +545,14 @@ GUEST_CODE static void guest_memset(void* s, uint8 c, int size)
p[i] = c;
}
+GUEST_CODE static void guest_memcpy(void* dst, void* src, int size)
+{
+ volatile uint8* d = (volatile uint8*)dst;
+ volatile uint8* s = (volatile uint8*)src;
+ for (int i = 0; i < size; i++)
+ d[i] = s[i];
+}
+
GUEST_CODE static noinline void
nested_enable_vmx_intel(uint64 cpu_id)
{
@@ -928,4 +947,26 @@ guest_handle_nested_create_vm(struct api_call_1* cmd, uint64 cpu_id)
}
}
+GUEST_CODE static noinline void
+guest_handle_nested_load_code(struct api_call_nested_load_code* cmd, uint64 cpu_id)
+{
+ uint64 vm_id = cmd->vm_id;
+ uint64 l2_code_addr = X86_SYZOS_ADDR_VM_CODE(cpu_id, vm_id);
+ uint64 l2_stack_addr = X86_SYZOS_ADDR_VM_STACK(cpu_id, vm_id);
+ // Code size = command size - header size - vm_id size.
+ uint64 l2_code_size = cmd->header.size - sizeof(struct api_call_header) - sizeof(uint64);
+ if (l2_code_size > KVM_PAGE_SIZE)
+ l2_code_size = KVM_PAGE_SIZE;
+ guest_memcpy((void*)l2_code_addr, (void*)cmd->insns,
+ l2_code_size);
+ if (get_cpu_vendor() == CPU_VENDOR_INTEL) {
+ nested_vmptrld(cpu_id, vm_id);
+ vmwrite(VMCS_GUEST_RIP, l2_code_addr);
+ vmwrite(VMCS_GUEST_RSP, l2_stack_addr + KVM_PAGE_SIZE - 8);
+ } else {
+ vmcb_write64(X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id), VMCB_GUEST_RIP, l2_code_addr);
+ vmcb_write64(X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id), VMCB_GUEST_RSP, l2_stack_addr + KVM_PAGE_SIZE - 8);
+ }
+}
+
#endif // EXECUTOR_COMMON_KVM_AMD64_SYZOS_H