From 0b3e5fe62f69564e0c611b639b5475f4299dceee Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 19 Jul 2024 15:49:53 +0800 Subject: [PATCH 1/2] pseudo_syscalls translation complete --- sources/syzkaller/pseudo_syscalls.md | 102 ++++++--------------------- 1 file changed, 22 insertions(+), 80 deletions(-) diff --git a/sources/syzkaller/pseudo_syscalls.md b/sources/syzkaller/pseudo_syscalls.md index 78109cc..9ab6b9c 100644 --- a/sources/syzkaller/pseudo_syscalls.md +++ b/sources/syzkaller/pseudo_syscalls.md @@ -1,41 +1,25 @@ --- -status: translating +status: translated title: "Pseudo-syscalls" author: Syzkaller Community collector: mudongliang collected_date: 20240229 translator: lidaxian121 +translated_date: 20240719 link: https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md --- -# Pseudo-syscalls +# 伪系统调用 -Besides regular system calls, a [syscall -description](syscall_descriptions.md) file can also contain -pseudo-syscalls. These are C functions defined in the -executor. When a test program uses a pseudo-syscall, the executor -will generate the pseudo-syscall function code in the resulting C program. +除了常规系统调用外,[系统调用描述](syscall_descriptions.md)文件也包含伪系统调用。它们是在执行器中定义的 C 函数。当测试程序使用伪系统调用时,执行器将在生成的 C 程序中生成伪系统调用函数。 -This allows a test program to have specific code blocks to perform -certain actions, they may also be used as more test-friendly wrappers -for primitive syscalls. +伪系统调用的存在使得测试程序可以拥有执行特定操作的特定代码块,它们还可以作为对原始系统调用的更友好的包装器使用。 -Use of pseudo-syscalls is generally **discouraged** because they ruin all -advantages of the declarative descriptions (declarativeness, conciseness, -fuzzer control over all aspects, possibility of global improvements to -the logic, static checking, fewer bugs, etc), increase maintenance burden, -are non-reusable and make C reproducers longer. However, syzlang is not -expressive enough to cover all possible cases, so use of pseudo-syscalls -needs to be considered on a case-by-cases basis (additional benefit, -amount of code, possibility of extending syzlang to cover this case, etc). +通常来说是**不建议**使用伪系统调用的,这是因为它们破坏了声明性描述的所有优势(声明性,简洁性,模糊器对所有方面的控制,全局逻辑改进的可能性,静态检查,减少错误等),增加了维护负担,不可重复使用,并且使 C 重现器(C reproducers)更长。然而,syzkaller 语言(syzlang)的表现力不足以涵盖所有可能的情况,因此需要根据具体情况考虑是否使用伪系统调用(额外的好处、代码量、扩展 syzkaller 语言以涵盖此情况的可能性等)。 -## How to add a pseudo-syscall to the executor +## 如何将伪系统调用添加到执行器中 -First, think about the scope of the pseudo-syscall and which systems and -subsystems it will be related to. The executor includes a fixed set of C -header files containing the code of the pseudo-syscalls. Check if the -new one can fit in one of the existing files before creating a new -one. These header files are defined in [gen.go](../pkg/csource/gen.go): +首先,考虑伪系统调用的范围以及它将涉及的系统和子系统。执行器包含一组固定的 C 头文件,其中包含伪系统调用的代码。在创建新文件之前,检查新文件是否可以适应现有文件之一。这些头文件在 [gen.go](https://chat.openai.com/pkg/csource/gen.go) 中定义: executorFilenames := []string{ "common_linux.h", @@ -54,40 +38,22 @@ one. These header files are defined in [gen.go](../pkg/csource/gen.go): "kvm_amd64.S.h", } -For instance, if our new pseudo-syscall is Linux-specific, then -[common_linux.h](../executor/common_linux.h) would be the place to put it. +例如,如果我们的新伪系统调用特定于 Linux,则 [common_linux.h](https://chat.openai.com/executor/common_linux.h) 将是放置它的地方。 -The actual pseudo-syscall function may look something like this: +真正的伪系统调用函数可能看起来就像下面的这个例子一样: #if SYZ_EXECUTOR || __NR_syz_mycall /* Add all the necessary #include and #define headers */ - + static long syz_mycall(volatile long a0, volatile long a1) { /* Function body */ } #endif -Make sure that all the function requirements are met and that it can -be compiled. Note that the function name must start with "syz_". It may -also take a different number of arguments. Type of arguments must be -`volatile long`, return type - `long`. `long` is required to avoid -potential calling convention issues because it is casted to a function -pointer that accepts `long`'s. The reason for `volatile` is interesting: -lots of libc functions are annotated with various argument constraints -(e.g. this argument should not be `NULL`, or that argument must be a -valid file descriptor); C reproducers may call these functions with -constant arguments and compiler may see that some of these constraints -are violated (e.g. passing `NULL` to a `non-NULL` argument, or passing -`-1` as file descriptor) and produce errors/warnings. `volatile` prevents -that. - -Now, to handle the pseudo-syscall properly we have to update the -`isSupportedSyzkall` in -[syscalls_linux.go](../pkg/host/syscalls_linux.go) and add a particular -case for this syscall, enabling it when necessary. If we want to enable -it unconditionally we can simply make `isSupportedSyzkall` return `true, -""` for it: +确保满足所有函数的要求并且可以编译成功。注意,函数名称必须以“syz_”开头。它还可以接受不同数量的参数。参数的类型必须是 `volatile long` ,返回类型是 `long` 。之所以需要使用 `long` ,是为了避免潜在的调用约定问题,因为它被转换为接受 `long` 的函数指针。用 `volatile` 的原因很有趣:许多libc函数都用各种参数约束注释(例如,此参数不应为 `NULL` ,或者该参数必须是有效的文件描述符);复现程序(C reproducers)可能使用常量参数调用这些函数,而编译器可能会看到某些约束被违反(例如,将 `NULL` 传递给 `非 NULL` 参数,或者将 `-1` 作为文件描述符传递),并生成错误或者警告。使用 `volatile` 可以防止这种情况。 + +现在,为了正确处理伪系统调用,我们必须更新 [syscalls_linux.go](https://chat.openai.com/pkg/host/syscalls_linux.go) 中的 `isSupportedSyzkall` 并为某个系统调用添加特定的情况,必要时启用它。如果我们想无条件启用它,我们可以简单地让 `isSupportedSyzkall` 为其返回 `true,""`: func isSupportedSyzkall(sandbox string, c *prog.Syscall) (bool, string) { switch c.CallName { @@ -95,40 +61,16 @@ it unconditionally we can simply make `isSupportedSyzkall` return `true, case "syz_mycall": return true, "" -Finally, run `make generate`. Now you can use it in a syscall -description file as if it was a regular system call: +最后,运行 `make generate`。现在,你就可以在系统调用描述文件中使用它了,就像它就和常规系统调用一样: syz_mycall(arg0 pid, arg1 const[0])
-## External Dependencies - -The implementation must not use any external libraries nor external headers, -except for the most basic and standard ones (like `` and -``). In particular, it must not depend on libraries/headers -installed by additional packages nor on headers for recently added kernel -subsystems. External dependencies have proved to be brittle and easily cause -build breakage because all dependencies will be required for any build/run on -the fuzzer and any C reproducer. For example, packages/headers may be missing -on some distros, named differently, be of a wrong version, broken, or conflict -with other headers. Unfortunately, there is no way to reliably specify such -dependencies and requirements for C programs. Therefore, if the pseudo-syscall -requires definitions of some structures, constants, or helper functions, these -should be described in the executor code itself as minimally as possible (they -will be part of C reproducers). - -## Testing - -Each new pseudo-syscall should have at least one test in `sys/OS/test`. -See [Linux tests](/sys/linux/test) for an example. A tests is just a program -with checked syscall return values. There should be at least one test -that contains "the main successful scenario" of using the pseudo-syscall. -See [io_uring test](/sys/linux/test/io_uring) as a good example. -Such tests are important because they ensure that the pseudo-syscall code -does not contain "stupid" bugs (e.g. crash on NULL-deref each time), -that it is possible for the fuzzer to come up with the successful scenario -(as a combination of the pseudo-syscall and the surrounding descriptions) -and that it will continue to work in future. -See [Testing of descriptions](syscall_descriptions.md#testing) -for details about the tests. +## 外部依赖 + +伪系统调用的实现不能使用任何外部库或外部头文件,除了一些最基本和标准的库(比如 `` 和 `` )。特别是,它不能依赖于附加软件包安装的库或者头文件,也不能依赖于最近添加的内核子系统的头文件。外部依赖性已经被证明是脆弱的,并且很容易导致构建中断,因为在模糊测试器上的任何构建和运行都将需要所有依赖项都可靠。例如,软件包或者头文件可能在某些发行版上缺少,命名不同,版本错误,损坏,或与其他头文件冲突。不幸的是,无法可靠地指定此类依赖项以及 C 程序的要求。因此,如果伪系统调用需要某些结构,常量或辅助函数的定义,则这些应该尽可能简短地在执行器代码中描述(它们将成为复现程序(C reproducers)的一部分)。 + +## 测试 + +每个新的伪系统调用应该在 `sys/OS/test` 中至少有一个测试。参见 [Linux tests](https://chat.openai.com/sys/linux/test) 作为示例。测试只是一个程序,带有检查过的系统调用返回值。对于某个伪系统调用应该至少有一个测试包含使用它的“主要成功场景”。可以看看 [io_uring 测试](sys/linux/test/io_uring),这是一个很好的例子。这样的测试很重要,因为它们确保伪系统调用的代码不包含“愚蠢”的错误(例如,每次在 NULL-deref 上崩溃)。这样,模糊测试器才可以想出成功的方案(伪系统调用和周围描述的组合),并且在将来能够持续工作。有关测试的详细信息,请参见[描述的测试](syscall_descriptions.md#testing)。 From 4fa5947a7df0c45206cd71d2ae611eaca1121be3 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Wed, 14 Aug 2024 16:33:13 +0800 Subject: [PATCH 2/2] fix pseudo_syscalls.md based on review comments --- sources/syzkaller/pseudo_syscalls.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sources/syzkaller/pseudo_syscalls.md b/sources/syzkaller/pseudo_syscalls.md index 9ab6b9c..71da3aa 100644 --- a/sources/syzkaller/pseudo_syscalls.md +++ b/sources/syzkaller/pseudo_syscalls.md @@ -11,15 +11,15 @@ link: https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md # 伪系统调用 -除了常规系统调用外,[系统调用描述](syscall_descriptions.md)文件也包含伪系统调用。它们是在执行器中定义的 C 函数。当测试程序使用伪系统调用时,执行器将在生成的 C 程序中生成伪系统调用函数。 +除了常规系统调用外,[系统调用描述](https://github.com/hust-open-atom-club/TranslateProject/blob/master/sources/syzkaller/syscall_descriptions.md)文件也包含伪系统调用。它们是在执行器中定义的 C 函数。当测试程序使用伪系统调用时,执行器将在生成的 C 程序中生成伪系统调用函数。 -伪系统调用的存在使得测试程序可以拥有执行特定操作的特定代码块,它们还可以作为对原始系统调用的更友好的包装器使用。 +伪系统调用的存在使得测试程序可以拥有执行特定操作的特定代码块,它们还可以作为更加测试友好的原始系统调用包装器来使用。 通常来说是**不建议**使用伪系统调用的,这是因为它们破坏了声明性描述的所有优势(声明性,简洁性,模糊器对所有方面的控制,全局逻辑改进的可能性,静态检查,减少错误等),增加了维护负担,不可重复使用,并且使 C 重现器(C reproducers)更长。然而,syzkaller 语言(syzlang)的表现力不足以涵盖所有可能的情况,因此需要根据具体情况考虑是否使用伪系统调用(额外的好处、代码量、扩展 syzkaller 语言以涵盖此情况的可能性等)。 ## 如何将伪系统调用添加到执行器中 -首先,考虑伪系统调用的范围以及它将涉及的系统和子系统。执行器包含一组固定的 C 头文件,其中包含伪系统调用的代码。在创建新文件之前,检查新文件是否可以适应现有文件之一。这些头文件在 [gen.go](https://chat.openai.com/pkg/csource/gen.go) 中定义: +首先,考虑伪系统调用的范围以及它将涉及的系统和子系统。执行器包含一组固定的 C 头文件,其中包含伪系统调用的代码。在创建新文件之前,检查新伪系统调用是否可以适应现有文件之一。这些头文件在 [gen.go](https://github.com/google/syzkaller/blob/master/pkg/compiler/gen.go) 中定义: executorFilenames := []string{ "common_linux.h", @@ -38,22 +38,22 @@ link: https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md "kvm_amd64.S.h", } -例如,如果我们的新伪系统调用特定于 Linux,则 [common_linux.h](https://chat.openai.com/executor/common_linux.h) 将是放置它的地方。 +例如,如果我们的新伪系统调用特定于 Linux,则 [common_linux.h](https://github.com/google/syzkaller/blob/master/executor/common_linux.h) 将是放置它的地方。 真正的伪系统调用函数可能看起来就像下面的这个例子一样: #if SYZ_EXECUTOR || __NR_syz_mycall /* Add all the necessary #include and #define headers */ - + static long syz_mycall(volatile long a0, volatile long a1) { /* Function body */ } #endif -确保满足所有函数的要求并且可以编译成功。注意,函数名称必须以“syz_”开头。它还可以接受不同数量的参数。参数的类型必须是 `volatile long` ,返回类型是 `long` 。之所以需要使用 `long` ,是为了避免潜在的调用约定问题,因为它被转换为接受 `long` 的函数指针。用 `volatile` 的原因很有趣:许多libc函数都用各种参数约束注释(例如,此参数不应为 `NULL` ,或者该参数必须是有效的文件描述符);复现程序(C reproducers)可能使用常量参数调用这些函数,而编译器可能会看到某些约束被违反(例如,将 `NULL` 传递给 `非 NULL` 参数,或者将 `-1` 作为文件描述符传递),并生成错误或者警告。使用 `volatile` 可以防止这种情况。 +确保满足所有函数的要求并且可以编译成功。注意,函数名称必须以 "syz_" 开头。它还可以接受不同数量的参数。参数的类型必须是 `volatile long`,返回类型是 `long`。之所以需要使用 `long` ,是为了避免潜在的调用约定问题,因为它被转换为接受 `long` 的函数指针。用 `volatile` 的原因很有趣:许多libc函数都用各种参数约束注释(例如,此参数不应为 `NULL`,或者该参数必须是有效的文件描述符);复现程序(C reproducers)可能使用常量参数调用这些函数,而编译器可能会看到某些约束被违反(例如,将 `NULL` 传递给 `non-NULL` 参数,或者将 `-1` 作为文件描述符传递),并生成错误或者警告。使用 `volatile` 可以防止这种情况。 -现在,为了正确处理伪系统调用,我们必须更新 [syscalls_linux.go](https://chat.openai.com/pkg/host/syscalls_linux.go) 中的 `isSupportedSyzkall` 并为某个系统调用添加特定的情况,必要时启用它。如果我们想无条件启用它,我们可以简单地让 `isSupportedSyzkall` 为其返回 `true,""`: +现在,为了正确处理伪系统调用,我们必须更新 [syscalls_linux.go](https://github.com/google/syzkaller/blob/master/pkg/host/syscalls_linux.go) 中的 `isSupportedSyzkall` 并为某个系统调用添加特定的情况,必要时启用它。如果我们想无条件启用它,我们可以简单地让 `isSupportedSyzkall` 为其返回 `true,""`: func isSupportedSyzkall(sandbox string, c *prog.Syscall) (bool, string) { switch c.CallName { @@ -61,7 +61,7 @@ link: https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md case "syz_mycall": return true, "" -最后,运行 `make generate`。现在,你就可以在系统调用描述文件中使用它了,就像它就和常规系统调用一样: +最后,运行 `make generate`。现在,你可以将它当作系统调用描述文件中的普通系统调用一样使用: syz_mycall(arg0 pid, arg1 const[0]) @@ -69,8 +69,8 @@ link: https://github.com/google/syzkaller/blob/master/docs/pseudo_syscalls.md ## 外部依赖 -伪系统调用的实现不能使用任何外部库或外部头文件,除了一些最基本和标准的库(比如 `` 和 `` )。特别是,它不能依赖于附加软件包安装的库或者头文件,也不能依赖于最近添加的内核子系统的头文件。外部依赖性已经被证明是脆弱的,并且很容易导致构建中断,因为在模糊测试器上的任何构建和运行都将需要所有依赖项都可靠。例如,软件包或者头文件可能在某些发行版上缺少,命名不同,版本错误,损坏,或与其他头文件冲突。不幸的是,无法可靠地指定此类依赖项以及 C 程序的要求。因此,如果伪系统调用需要某些结构,常量或辅助函数的定义,则这些应该尽可能简短地在执行器代码中描述(它们将成为复现程序(C reproducers)的一部分)。 +伪系统调用的实现不能使用任何外部库或外部头文件,除了一些最基本和标准的库(比如 `` 和 `` )。特别是,它不能依赖于附加软件包安装的库或者头文件,也不能依赖于最近添加的内核子系统的头文件。外部依赖性已经被证明是脆弱的,并且很容易导致构建中断,因为模糊测试器上任何的构建和运行以及 C 复现器都需要所有依赖项。例如,软件包或者头文件可能在某些发行版上缺少,命名不同,版本错误,损坏,或与其他头文件冲突。不幸的是,无法可靠地指定此类依赖项以及 C 程序的要求。因此,如果伪系统调用需要某些结构,常量或辅助函数的定义,则这些应该尽可能简短地在执行器代码中描述(它们将成为复现程序(C reproducers)的一部分)。 ## 测试 -每个新的伪系统调用应该在 `sys/OS/test` 中至少有一个测试。参见 [Linux tests](https://chat.openai.com/sys/linux/test) 作为示例。测试只是一个程序,带有检查过的系统调用返回值。对于某个伪系统调用应该至少有一个测试包含使用它的“主要成功场景”。可以看看 [io_uring 测试](sys/linux/test/io_uring),这是一个很好的例子。这样的测试很重要,因为它们确保伪系统调用的代码不包含“愚蠢”的错误(例如,每次在 NULL-deref 上崩溃)。这样,模糊测试器才可以想出成功的方案(伪系统调用和周围描述的组合),并且在将来能够持续工作。有关测试的详细信息,请参见[描述的测试](syscall_descriptions.md#testing)。 +每个新的伪系统调用应该在 `sys/OS/test` 中至少有一个测试。参见 [Linux tests](https://github.com/google/syzkaller/blob/master/sys/linux/test) 作为示例。测试只是一个检查系统调用返回值的程序。对于某个伪系统调用应该至少有一个测试包含使用它的“主要成功场景”。可以看看 [io_uring 测试](https://github.com/google/syzkaller/blob/master/sys/linux/test/io_uring),这是一个很好的例子。这样的测试很重要,因为它们确保伪系统调用的代码不包含“愚蠢”的错误(例如,每次在 NULL-deref 上崩溃)。这样,模糊测试器才可以想出成功的方案(伪系统调用和周围描述的组合),并且在将来能够持续工作。有关测试的详细信息,请参见[描述的测试](https://github.com/hust-open-atom-club/TranslateProject/blob/master/sources/syzkaller/syscall_descriptions.md)。