From df949cd92b8e324cf57a033d3166077e6ab2ca79 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 6 Feb 2026 16:54:14 +0100 Subject: sys/linux/test: add SYZOS tests for nested GPR persistence Add two new SYZOS test cases to verify the persistence of Guest Physical Registers (GPRs) in nested virtualization scenario. These tests ensure that the hypervisor correctly saves and restores L2 GPRs during nested VM-exits and VM-entries, preventing register state corruption. --- .../test/amd64-syz_kvm_nested_gpr_persistence | 47 ++++++++++++++++++++++ .../amd64-syz_kvm_nested_gpr_persistence_syzos | 32 +++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 sys/linux/test/amd64-syz_kvm_nested_gpr_persistence create mode 100644 sys/linux/test/amd64-syz_kvm_nested_gpr_persistence_syzos (limited to 'sys/linux') diff --git a/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence b/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence new file mode 100644 index 000000000..b1ee8ad6b --- /dev/null +++ b/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence @@ -0,0 +1,47 @@ +# +# 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: +# 1. Sets R15 to a magic value. +# 2. Does UEXIT(1) to L1. +# 3. L1 clobbers R15 and resumes L2. +# 4. L2 does UEXIT(R15). +# 5. Host verifies that L2's R15 was preserved despite L1 clobber. +# +# L2 Payload: +# 49bf563412efbeadde00 movabs $0x00deadbeef123456, %r15 +# b801000000 mov $1, %rax +# 48ba0001040000000000 mov $0x40100, %rdx +# 488902 mov %rax, (%rdx) --> UEXIT(1) +# 4c89f8 mov %r15, %rax +# 488902 mov %rax, (%rdx) --> UEXIT(R15) +# f4 hlt +# +# L1 Clobber: +# 49bf0000000000000000 movabs $0, %r15 +# +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, "49bf563412efbeadde00b80100000048ba00010400000000004889024c89f8488902f4"}}, @nested_vmlaunch={AUTO, AUTO, 0x0}, @code={AUTO, AUTO, {"49bf0000000000000000", 0xc3}}, @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) + +# 1. Run until first UEXIT (L2 notifies it's ready). +# Expected L2 exit code 1 -> L1 uexit 0x0100000000000001. +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0x0100000000000001) + +# 2. Run until second UEXIT (L2 returns its R15). +# L1 clobbered its own R15 in between. +# Expected L2 exit code 0x00deadbeef123456 -> L1 uexit 0x01deadbeef123456. +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0x01deadbeef123456) + +# Final exit. +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0xffffffffffffffff) diff --git a/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence_syzos b/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence_syzos new file mode 100644 index 000000000..d3708afab --- /dev/null +++ b/sys/linux/test/amd64-syz_kvm_nested_gpr_persistence_syzos @@ -0,0 +1,32 @@ +# +# 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: +# 1. Sets R15 to a magic value. +# 2. Does UEXIT(1) to L1. +# 3. L1 clobbers R15 and resumes L2. +# 4. L2 does UEXIT(R15). +# 5. Host verifies that L2's R15 was preserved despite L1 clobber. +# +r3 = syz_kvm_add_vcpu$x86(r2, &AUTO={0x0, &AUTO=[@enable_nested={AUTO, AUTO, 0x0}, @nested_create_vm={AUTO, AUTO, 0x0}, @nested_load_syzos={AUTO, AUTO, {0x0, 0x10, [@code={AUTO, AUTO, {"49bf563412efbeadde00", 0xc3}}, @uexit={AUTO, AUTO, 0x1}, @code={AUTO, AUTO, {"4c89f848ba0001040000000000488902", 0xc3}}]}}, @nested_vmlaunch={AUTO, AUTO, 0x0}, @code={AUTO, AUTO, {"49bf0000000000000000", 0xc3}}, @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) + +# 1. Run until first UEXIT (L2 notifies it's ready). +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0x0100000000000001) + +# 2. Run until second UEXIT (L2 returns its R15). +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0x01deadbeef123456) + +# Final exit. +# +ioctl$KVM_RUN(r3, AUTO, 0x0) +syz_kvm_assert_syzos_uexit$x86(r3, r5, 0xffffffffffffffff) -- cgit mrf-deployment