diff options
| author | Alexander Potapenko <glider@google.com> | 2026-01-27 17:20:16 +0100 |
|---|---|---|
| committer | Alexander Potapenko <glider@google.com> | 2026-02-09 09:43:36 +0000 |
| commit | d36c2ba14701aaa8b613b9babb65720a9b510bf9 (patch) | |
| tree | 356dfd2ea04462f093ba3598f2a6ead48d3ac2c4 /executor/common_kvm_amd64.h | |
| parent | dcd3f1a34151f50991c29aa21677ba6f09159da8 (diff) | |
executor: sys/linux: Implement nested SYZOS loading
This commit introduces the `SYZOS_API_NESTED_LOAD_SYZOS` command to
enable running full SYZOS programs within a nested L2 guest, enhancing
fuzzing capabilities for nested virtualization.
Key changes include:
- Nested SYZOS Execution: The new command loads a SYZOS program into an
L2 VM, setting up its execution environment.
- ABI Refinement: Program size is now passed via the shared `syzos_globals`
memory region instead of registers, standardizing the ABI for L1 and L2.
- L2 State Management: Improved saving and restoring of L2 guest GPRs
across VM-exits using inline assembly wrappers for Intel and AMD.
- Nested UEXIT Propagation: Intercepts EPT/NPT faults on the exit page to
capture the L2 exit code from saved registers and forward it to L0 with
an incremented nesting level.
- L2 Memory Management: Updates to L2 page table setup, including skipping
NO_HOST_MEM regions to force exits, and a new `l2_gpa_to_pa` helper.
Diffstat (limited to 'executor/common_kvm_amd64.h')
| -rw-r--r-- | executor/common_kvm_amd64.h | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/executor/common_kvm_amd64.h b/executor/common_kvm_amd64.h index 474bc875b..c5d7c6983 100644 --- a/executor/common_kvm_amd64.h +++ b/executor/common_kvm_amd64.h @@ -206,6 +206,7 @@ static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g #endif #if SYZ_EXECUTOR || __NR_syz_kvm_setup_syzos_vm || __NR_syz_kvm_add_vcpu + // SYZOS guest virtual memory layout (must be in sync with executor/kvm.h): static const struct mem_region syzos_mem_regions[] = { // AMD64 fixed data structures (5 pages: Zero, GDT, PML4, PDP, PD). @@ -250,6 +251,7 @@ struct kvm_syz_vm { void* user_text; void* gpa0_mem; void* pt_pool_mem; + void* globals_mem; }; #endif @@ -1100,19 +1102,16 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat #define RFLAGS_1_BIT (1ULL << 1) #define RFLAGS_IF_BIT (1ULL << 9) -static void reset_cpu_regs(int cpufd, int cpu_id, size_t text_size) +static void reset_cpu_regs(int cpufd, uint64 rip, uint64 cpu_id) { struct kvm_regs regs; memset(®s, 0, sizeof(regs)); // RFLAGS.1 must be 1, RFLAGS.IF enables interrupts. regs.rflags |= RFLAGS_1_BIT | RFLAGS_IF_BIT; - // PC points to the relative offset of guest_main() within the guest code. - regs.rip = executor_fn_guest_addr(guest_main); + regs.rip = rip; regs.rsp = X86_SYZOS_ADDR_STACK0; - // Pass parameters to guest_main(). - regs.rdi = text_size; - regs.rsi = cpu_id; + regs.rdi = cpu_id; ioctl(cpufd, KVM_SET_REGS, ®s); } @@ -1126,7 +1125,15 @@ static void install_user_code(struct kvm_syz_vm* vm, int cpufd, int cpu_id, cons memcpy(target, text, text_size); setup_gdt_ldt_pg(vm, cpufd, cpu_id); setup_cpuid(cpufd); - reset_cpu_regs(cpufd, cpu_id, text_size); + + uint64 entry_rip = executor_fn_guest_addr(guest_main); + reset_cpu_regs(cpufd, entry_rip, cpu_id); + + // Pass the text size via the shared globals page. + if (vm->globals_mem) { + struct syzos_globals* globals = (struct syzos_globals*)vm->globals_mem; + globals->text_sizes[cpu_id] = text_size; + } } #endif @@ -1196,6 +1203,8 @@ static void setup_vm(int vmfd, struct kvm_syz_vm* vm) vm->gpa0_mem = next.addr; if (r->gpa == X86_SYZOS_ADDR_PT_POOL) vm->pt_pool_mem = next.addr; + if (r->gpa == X86_SYZOS_ADDR_GLOBALS) + vm->globals_mem = next.addr; if (r->gpa == X86_SYZOS_ADDR_BOOT_ARGS) { boot_args = (struct syzos_boot_args*)next.addr; @@ -1326,4 +1335,4 @@ static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1, volat } #endif -#endif // EXECUTOR_COMMON_KVM_AMD64_H
\ No newline at end of file +#endif // EXECUTOR_COMMON_KVM_AMD64_H |
