github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/docs/pseudo_syscalls.md (about) 1 # Pseudo-syscalls 2 3 Besides regular system calls, a [syscall 4 description](syscall_descriptions.md) file can also contain 5 pseudo-syscalls. These are C functions defined in the 6 executor. When a test program uses a pseudo-syscall, the executor 7 will generate the pseudo-syscall function code in the resulting C program. 8 9 This allows a test program to have specific code blocks to perform 10 certain actions, they may also be used as more test-friendly wrappers 11 for primitive syscalls. 12 13 Use of pseudo-syscalls is generally **discouraged** because they ruin all 14 advantages of the declarative descriptions (declarativeness, conciseness, 15 fuzzer control over all aspects, possibility of global improvements to 16 the logic, static checking, fewer bugs, etc), increase maintenance burden, 17 are non-reusable and make C reproducers longer. However, syzlang is not 18 expressive enough to cover all possible cases, so use of pseudo-syscalls 19 needs to be considered on a case-by-cases basis (additional benefit, 20 amount of code, possibility of extending syzlang to cover this case, etc). 21 22 ## How to add a pseudo-syscall to the executor 23 24 First, think about the scope of the pseudo-syscall and which systems and 25 subsystems it will be related to. The executor includes a fixed set of C 26 header files `executor/common*.h` containing the code of the pseudo-syscalls. 27 Check if the new one can fit in one of the existing files before creating 28 a new one. 29 30 For instance, if our new pseudo-syscall is Linux-specific, then 31 [common_linux.h](../executor/common_linux.h) would be the place to put it. 32 33 The actual pseudo-syscall function may look something like this: 34 35 #if SYZ_EXECUTOR || __NR_syz_mycall 36 /* Add all the necessary #include and #define headers */ 37 38 static long syz_mycall(volatile long a0, volatile long a1) 39 { 40 /* Function body */ 41 } 42 #endif 43 44 Make sure that all the function requirements are met and that it can 45 be compiled. Note that the function name must start with "syz_". It may 46 also take a different number of arguments. Type of arguments must be 47 `volatile long`, return type - `long`. `long` is required to avoid 48 potential calling convention issues because it is casted to a function 49 pointer that accepts `long`'s. The reason for `volatile` is interesting: 50 lots of libc functions are annotated with various argument constraints 51 (e.g. this argument should not be `NULL`, or that argument must be a 52 valid file descriptor); C reproducers may call these functions with 53 constant arguments and compiler may see that some of these constraints 54 are violated (e.g. passing `NULL` to a `non-NULL` argument, or passing 55 `-1` as file descriptor) and produce errors/warnings. `volatile` prevents 56 that. 57 58 Now, to handle the pseudo-syscall properly we have to update the 59 `linuxSyscallChecks` in 60 [linux_syscalls.go](../pkg/vminfo/linux_syscalls.go) and add a particular 61 case for this syscall, enabling it when necessary. If we want to enable 62 it unconditionally we can simply use `alwaysSupported` for it. 63 64 Finally, run `make generate`. Now you can use it in a syscall 65 description file as if it was a regular system call: 66 67 syz_mycall(arg0 pid, arg1 const[0]) 68 69 <div id="dependencies"/> 70 71 ## External Dependencies 72 73 The implementation must not use any external libraries nor external headers, 74 except for the most basic and standard ones (like `<unistd.h>` and 75 `<sys/mman.h>`). In particular, it must not depend on libraries/headers 76 installed by additional packages nor on headers for recently added kernel 77 subsystems. External dependencies have proved to be brittle and easily cause 78 build breakage because all dependencies will be required for any build/run on 79 the fuzzer and any C reproducer. For example, packages/headers may be missing 80 on some distros, named differently, be of a wrong version, broken, or conflict 81 with other headers. Unfortunately, there is no way to reliably specify such 82 dependencies and requirements for C programs. Therefore, if the pseudo-syscall 83 requires definitions of some structures, constants, or helper functions, these 84 should be described in the executor code itself as minimally as possible (they 85 will be part of C reproducers). 86 87 ## Testing 88 89 Each new pseudo-syscall should have at least one test in `sys/OS/test`. 90 See [Linux tests](/sys/linux/test) for an example. A tests is just a program 91 with checked syscall return values. There should be at least one test 92 that contains "the main successful scenario" of using the pseudo-syscall. 93 See [io_uring test](/sys/linux/test/io_uring) as a good example. 94 Such tests are important because they ensure that the pseudo-syscall code 95 does not contain "stupid" bugs (e.g. crash on NULL-deref each time), 96 that it is possible for the fuzzer to come up with the successful scenario 97 (as a combination of the pseudo-syscall and the surrounding descriptions) 98 and that it will continue to work in future. 99 See [Testing of descriptions](syscall_descriptions.md#testing) 100 for details about the tests.