aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2026-01-15 10:45:43 +0100
committerAlexander Potapenko <glider@google.com>2026-01-16 09:47:24 +0000
commit67ef04e1ef9d40a76d1e2cb97ffa3adbfa51bdb5 (patch)
treee07f4076ee9eec106b4969694928558aacdc610b
parent67945471d459ce8031b65988d49bf03b726ae691 (diff)
executor: sys/linux: Add VCPU fd to `syz_kvm_assert_syzos_uexit`
Enhance the debugging capabilities of C reproducers by passing the VCPU file descriptor to the syz_kvm_assert_syzos_uexit function. With access to the VCPU fd, the function can now dump the VCPU's register state upon assertion failure, providing critical context for debugging guest execution issues.
-rw-r--r--executor/common_kvm_386.h2
-rw-r--r--executor/common_kvm_amd64.h62
-rw-r--r--executor/common_kvm_arm64.h27
-rw-r--r--sys/linux/dev_kvm_amd64.txt2
-rw-r--r--sys/linux/dev_kvm_arm64.txt2
5 files changed, 79 insertions, 16 deletions
diff --git a/executor/common_kvm_386.h b/executor/common_kvm_386.h
index 5c8498492..2eba3ee18 100644
--- a/executor/common_kvm_386.h
+++ b/executor/common_kvm_386.h
@@ -21,7 +21,7 @@ static long syz_kvm_add_vcpu(volatile long a0, volatile long a1)
#endif
#if SYZ_EXECUTOR || __NR_syz_kvm_assert_syzos_uexit
-static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1)
+static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1, volatile long a2)
{
return 0;
}
diff --git a/executor/common_kvm_amd64.h b/executor/common_kvm_amd64.h
index 0c49f07a0..170d658da 100644
--- a/executor/common_kvm_amd64.h
+++ b/executor/common_kvm_amd64.h
@@ -1202,18 +1202,66 @@ static long syz_kvm_add_vcpu(volatile long a0, volatile long a1)
}
#endif
-#if SYZ_EXECUTOR || __NR_syz_kvm_assert_syzos_uexit
-static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1)
+#if !SYZ_EXECUTOR && __NR_syz_kvm_assert_syzos_uexit
+static void dump_vcpu_state(int cpufd, struct kvm_run* run)
{
- struct kvm_run* run = (struct kvm_run*)a0;
- uint64 expect = a1;
+ struct kvm_regs regs;
+ ioctl(cpufd, KVM_GET_REGS, &regs);
+ struct kvm_sregs sregs;
+ ioctl(cpufd, KVM_GET_SREGS, &sregs);
+ fprintf(stderr, "KVM_RUN structure:\n");
+ fprintf(stderr, " exit_reason: %d\n", run->exit_reason);
+ fprintf(stderr, " hardware_entry_failure_reason: 0x%llx\n",
+ run->fail_entry.hardware_entry_failure_reason);
+ fprintf(stderr, "VCPU registers:\n");
+ fprintf(stderr, " rip: 0x%llx, rsp: 0x%llx, rflags: 0x%llx\n", regs.rip,
+ regs.rsp, regs.rflags);
+ fprintf(stderr, "VCPU sregs:\n");
+ fprintf(stderr, " cr0: 0x%llx, cr2: 0x%llx, cr3: 0x%llx, cr4: 0x%llx\n",
+ sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4);
+ fprintf(stderr, " efer: 0x%llx (LME=%d)\n", sregs.efer,
+ (sregs.efer & X86_EFER_LME) ? 1 : 0);
+ fprintf(stderr, " cs: s=0x%x, b=0x%llx, limit=0x%x, type=%d, l=%d, db=%d\n",
+ sregs.cs.selector, sregs.cs.base, sregs.cs.limit, sregs.cs.type,
+ sregs.cs.l, sregs.cs.db);
+ fprintf(stderr, " ds: s=0x%x, b=0x%llx, limit=0x%x, type=%d, db=%d\n",
+ sregs.ds.selector, sregs.ds.base, sregs.ds.limit, sregs.ds.type,
+ sregs.ds.db);
+ fprintf(stderr, " tr: s=0x%x, b=0x%llx, limit=0x%x, type=%d, db=%d\n",
+ sregs.tr.selector, sregs.tr.base, sregs.tr.limit, sregs.tr.type,
+ sregs.tr.db);
+ fprintf(stderr, " idt: b=0x%llx, limit=0x%x\n", sregs.idt.base,
+ sregs.idt.limit);
+}
+#endif
- if (!run || (run->exit_reason != KVM_EXIT_MMIO) || (run->mmio.phys_addr != X86_SYZOS_ADDR_UEXIT)) {
+#if SYZ_EXECUTOR || __NR_syz_kvm_assert_syzos_uexit
+static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1, volatile long a2)
+{
+#if !SYZ_EXECUTOR
+ int cpufd = (int)a0;
+#endif
+ struct kvm_run* run = (struct kvm_run*)a1;
+ uint64 expect = a2;
+
+ if (!run || (run->exit_reason != KVM_EXIT_MMIO) ||
+ (run->mmio.phys_addr != X86_SYZOS_ADDR_UEXIT)) {
+#if !SYZ_EXECUTOR
+ fprintf(stderr, "[SYZOS-DEBUG] Assertion Triggered on VCPU %d\n", cpufd);
+ dump_vcpu_state(cpufd, run);
+#endif
errno = EINVAL;
return -1;
}
- if ((((uint64*)(run->mmio.data))[0]) != expect) {
+ uint64 actual_code = ((uint64*)(run->mmio.data))[0];
+ if (actual_code != expect) {
+#if !SYZ_EXECUTOR
+ fprintf(stderr, "[SYZOS-DEBUG] Exit Code Mismatch on VCPU %d\n", cpufd);
+ fprintf(stderr, " Expected: 0x%lx\n", (unsigned long)expect);
+ fprintf(stderr, " Actual: 0x%lx\n", (unsigned long)actual_code);
+ dump_vcpu_state(cpufd, run);
+#endif
errno = EDOM;
return -1;
}
@@ -1221,4 +1269,4 @@ static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1)
}
#endif
-#endif // EXECUTOR_COMMON_KVM_AMD64_H \ No newline at end of file
+#endif // EXECUTOR_COMMON_KVM_AMD64_H
diff --git a/executor/common_kvm_arm64.h b/executor/common_kvm_arm64.h
index 0663dcd1c..58678a9df 100644
--- a/executor/common_kvm_arm64.h
+++ b/executor/common_kvm_arm64.h
@@ -362,17 +362,32 @@ static long syz_kvm_vgic_v3_setup(volatile long a0, volatile long a1, volatile l
#endif
#if SYZ_EXECUTOR || __NR_syz_kvm_assert_syzos_uexit
-static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1)
+static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1,
+ volatile long a2)
{
- struct kvm_run* run = (struct kvm_run*)a0;
- uint64 expect = a1;
+#if !SYZ_EXECUTOR
+ int cpufd = (int)a0;
+#endif
+ struct kvm_run* run = (struct kvm_run*)a1;
+ uint64 expect = a2;
- if (!run || (run->exit_reason != KVM_EXIT_MMIO) || (run->mmio.phys_addr != ARM64_ADDR_UEXIT)) {
+ if (!run || (run->exit_reason != KVM_EXIT_MMIO) ||
+ (run->mmio.phys_addr != ARM64_ADDR_UEXIT)) {
+#if !SYZ_EXECUTOR
+ fprintf(stderr, "[SYZOS-DEBUG] Assertion Triggered on VCPU %d\n", cpufd);
+#endif
errno = EINVAL;
return -1;
}
- if ((((uint64*)(run->mmio.data))[0]) != expect) {
+ uint64_t actual_code = ((uint64_t*)(run->mmio.data))[0];
+ if (actual_code != expect) {
+#if !SYZ_EXECUTOR
+ fprintf(stderr, "[SYZOS-DEBUG] Exit Code Mismatch on VCPU %d\n", cpufd);
+ fprintf(stderr, " Expected: 0x%lx\n", (unsigned long)expect);
+ fprintf(stderr, " Actual: 0x%lx\n",
+ (unsigned long)actual_code);
+#endif
errno = EDOM;
return -1;
}
@@ -399,4 +414,4 @@ static long syz_kvm_assert_reg(volatile long a0, volatile long a1, volatile long
}
#endif
-#endif // EXECUTOR_COMMON_KVM_ARM64_H \ No newline at end of file
+#endif // EXECUTOR_COMMON_KVM_ARM64_H
diff --git a/sys/linux/dev_kvm_amd64.txt b/sys/linux/dev_kvm_amd64.txt
index 7ac8028d9..acd80540c 100644
--- a/sys/linux/dev_kvm_amd64.txt
+++ b/sys/linux/dev_kvm_amd64.txt
@@ -24,7 +24,7 @@ syz_kvm_setup_syzos_vm$x86(fd fd_kvmvm, usermem vma[1024]) kvm_syz_vm$x86
syz_kvm_add_vcpu$x86(vm kvm_syz_vm$x86, text ptr[in, kvm_text$x86]) fd_kvmcpu (no_squash)
# Test assertions, will not be used by the fuzzer.
-syz_kvm_assert_syzos_uexit$x86(run kvm_run_ptr, exitcode intptr) (no_generate)
+syz_kvm_assert_syzos_uexit$x86(cpufd fd_kvmcpu, run kvm_run_ptr, exitcode intptr) (no_generate)
syz_kvm_assert_syzos_kvm_exit$x86(run kvm_run_ptr, exitcode intptr) (no_generate)
# Pseudo call that setups VCPU into a reasonable interesting state for execution.
diff --git a/sys/linux/dev_kvm_arm64.txt b/sys/linux/dev_kvm_arm64.txt
index f4c724606..35ff5f73d 100644
--- a/sys/linux/dev_kvm_arm64.txt
+++ b/sys/linux/dev_kvm_arm64.txt
@@ -27,7 +27,7 @@ kvm_num_irqs = 32, 64, 128, 256, 512
syz_kvm_vgic_v3_setup(fd fd_kvmvm, ncpus intptr[0:4], nirqs flags[kvm_num_irqs]) fd_kvmdev
# Test assertions, will not be used by the fuzzer.
-syz_kvm_assert_syzos_uexit$arm64(run kvm_run_ptr, exitcode int64) (no_generate)
+syz_kvm_assert_syzos_uexit$arm64(cpufd fd_kvmcpu, run kvm_run_ptr, exitcode int64) (no_generate)
syz_kvm_assert_reg(fd fd_kvmcpu, reg int64, value int64) (no_generate)
syz_kvm_assert_syzos_kvm_exit$arm64(run kvm_run_ptr, exitcode int64) (no_generate)