Support new syscalls
Last updated: Mar. 23, 2026 by Sungwoo Kim.
XNU is a hybrid kernel composed of BSD (POSIX interface) and Mach (RPC layer). Although Syzkaller supports XNU syscall fuzzing, its coverage is limited to the legacy BSD surface and leaves most Mach and newly introduced BSD syscalls uncovered. As a result, vulnerabilities in Mach and newer BSD interfaces are easily missed. To cover these paths, Syzkaller must be provided with accurate syscall descriptions in syzlang.
Automatically converting syscalls to syzlang is a known challenge1. While several studies2345 proposed automatic extraction using profiling, symbolic execution, and static analysis, their implementations are no longer maintained and are not compatible with current kernels. I therefore developed a new tool with generality as a primary design goal, so it remains compatible across multiple XNU versions, including future releases where possible.
To achieve this, I implemented a lightweight transpiler, c2syz, which converts C function definitions into syzlang using an LLVM pass. It consumes Mach and BSD syscall definitions from the kernel sources and emits syzlang descriptions. The source is available at https://github.com/swkim101/syz-xnu/tree/main/c2syz
Syscalls conversion
extern kern_return_t pid_for_task(
mach_port_name_t t,
int *x
);
is converted to
pid_for_task(t mach_port_name_t, x int_inout) kern_return_t
via a simple one-on-one mapping. Types are recursively resolved through typedef chains until primitive types are reached. Nested structures are more complex to resolve:
typedef struct mach_port_options {
uint32_t flags;
mach_port_limits_t mpl;
union {
uint64_t reserved[2];
mach_port_name_t work_interval_port;
[snip]
As shown, the union is anonymous, which is not allowed in syzlang. In this case, c2syz assigns a name with identifiers as follows:
struct_mach_port_options {
flags uint32_t
mpl mach_port_limits_t
unname_2 unnamed_110871574501872
}
unnamed_110871574501872 [
reserved uint64_t_2
work_interval_port mach_port_name_t
service_port_info mach_service_port_info_t
service_port_name mach_port_name_t
]
This approach allows c2syz to generate both Mach and BSD syscall descriptions in syzlang.
Tip for mach_port_t
The primary role of the Mach kernel is RPC handling. All RPC operations require mach_port_t, an abstract identifier used by Mach IPC. Accordingly, Mach syscalls frequently produce and/or consume mach_port_t values.
From a fuzzing perspective, generating a valid mach_port_t is important. Otherwise, invalid mach_port_t values fail early validation, and fuzzing inputs cannot reach core logic. This can be addressed using the resource keyword6. In practice, defining resource mach_port_t[int32] resolves the dependency issue.
syzkaller/sys/darwin/bsd.txt and syzkaller/sys/darwin/mach.txt include the outputs.
Limitation
c2syz cannot resolve complex dependencies between system calls. Also, c2syz naively assumes all pointer arguments are both readable and writable. To resolve the dependency and pointer semantics, IMF7, Moonshine5, syzgen3, Healer8, and SyzDescribe9 provide more advanced design strategies.
- https://github.com/google/syzkaller/issues/590 back
- https://www.usenix.org/system/files/atc22-sun.pdf back
- https://dl.acm.org/doi/pdf/10.1145/3460120.3484564 back
- https://ieeexplore.ieee.org/document/10646807 back
- https://dl.acm.org/doi/pdf/10.1145/3133956.3134103 back
- https://github.com/google/syzkaller/blob/master/docs/syscall_descriptions_syntax.md#resources back
- https://acmccs.github.io/papers/p2345-hanA.pdf back
- https://dl.acm.org/doi/pdf/10.1145/3477132.3483547 back
- https://ieeexplore.ieee.org/document/10179298 back