OSS-Fuzz 是一项免费服务,为开源项目持续运行模糊器。此 GitHub 存储库管理该服务,注册加入通过拉取请求处理。
一旦项目与 OSS-Fuzz 集成,与该项目关联的模糊器每天都会运行——持续且无限期地运行。当发现错误时,OSS-Fuzz 会通过电子邮件通知维护者,并且还有一个仪表板,其中包含有关所有已发现问题的详细信息(堆栈跟踪、用于重现问题的工件等等)。
与 OSS-Fuzz 集成的好处是,管理模糊器执行和分析结果的大部分方面都由 OSS-Fuzz 本身完成。这在模糊测试中很重要,因为模糊器会随着时间的推移建立历史配置文件,这意味着持续分析对于最大化结果至关重要。在一个项目中,我们在博客文章中详细介绍了该项目,模糊测试在几个月内只是临时运行,没有报告任何特定问题。然而,在与 OSS-Fuzz 集成后,该服务在连续执行大约一周内报告了一个问题。在这种情况下,一个严重的安全性问题仅仅是因为 OSS-Fuzz 的持续分析才被发现。
哪些项目可以集成到 OSS-fuzz 中?
要获得集成资格,开源项目必须服务于全球基础设施的关键目的。这通常意味着更大的用户群体依赖该项目,或者其他重要的开源项目依赖它。关于项目是否具有安全关键性的判断由 OSS-Fuzz 维护者逐个项目进行。要了解维护者是否会接受您的项目,请创建一个拉取请求以集成您的项目,他们将通过 PR 通知您项目是否被接受。
此外,您必须使用 OSS-Fuzz 支持的一种或多种语言编写项目。在撰写本文时,这些语言是 C、C++、Go、Rust、Python、Java 和 Swift。
OSS-Fuzz 现阶段管理着 500 多个项目的模糊测试,包括 Kubernetes、Istio、Envoy、VLC、OpenSSL、Containerd、Binutils、Spidermonkey 和 systemd。
将项目集成到 OSS-Fuzz 中
将项目集成到 OSS-Fuzz 中的两个主要要素是一组可以分析您的开源项目的模糊器,以及在 OSS-Fuzz 环境中构建模糊器所需的基础设施粘合剂。
创建一组模糊器
为给定的开源项目创建一组模糊器很大程度上取决于项目本身。这是一个简单的示例,演示了一个名为 char_lib.c
的单个文件中的自包含库,该库公开了一个函数
// Count the number of lowercase letters
// input must be a null-terminated string.
int count_lowercase_letters(char *input);
为此库编写一个简单的模糊器
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// wrap input in null-terminated string
char *ns = malloc(size+1);
memcpy(ns, data, size);
ns[size] = '\0';
count_lowercase_letters(ns);
free(ns);
}
将此函数放在 Git 存储库根目录中名为 fuzz_char_lib.c
的文件中。此时,您可以通过编译 char_lib.c
和 fuzz_char_lib.c
来模糊测试您的库
clang -fsanitize=fuzzer-no-link char_lib.c -c -o char_lib.o
clang -fsanitize=fuzzer-no-link fuzz_char_lib.c -c -o fuzz_char_lib.o
clang -fsanitize=fuzzer fuzz_char_lib.o char_lib.o -o fuzzer
最后,运行模糊器
$ ./fuzzer
OSS-Fuzz 基础设施设置
要将示例库集成到 OSS-Fuzz 中,您必须创建三个文件:project.yaml
、Dockerfile
和 build.sh
。这些是在 OSS-Fuzz 上创建项目文件夹所需的组件(请参阅此 Kubernetes 集成作为一个详细的例子。)
Project.yaml
此 YAML 文件包含有关项目的管理数据。文件中最重要的两个部分是联系人列表(primary_contact 和 auto_ccs)和项目的编程语言。这是文件
homepage: "https://github.com/AdaLogics/oss-fuzz-example"
main_repo: 'https://github.com/AdaLogics/oss-fuzz-example'
primary_contact: "adam@example.com"
auto_ccs :
- "david@example.com"
language: c
Dockerfile
Dockerfile 负责构建一个容器,该容器下载相关的源代码存储库,并下载和配置依赖项。OSS-Fuzz 执行多次构建以适应不同的消毒器和各种模糊引擎,因此容器仅创建一个可以构建项目的构建脚本,但不运行构建脚本本身。这是一个示例 Dockerfile
FROM gcr.io/oss-fuzz-base/base-builder
RUN git clone https://github.com/AdaLogics/oss-fuzz-example
COPY build.sh $SRC/build.sh
WORKDIR $SRC/oss-fuzz-example
Build.sh
build.sh
脚本构建项目。它需要使用一些特定的环境变量来表示编译器和编译器标志,而不是指定编译器,因为 OSS-Fuzz 以许多不同的方式构建每个项目(不同的模糊器、不同的标志等等)。最重要的环境变量是 CC、CXX、CFLAGS、CXXFLAGS 和 LIB_FUZZING_ENGINE。前四个标志是常见的编译器变量。但是,LIB_FUZZING_ENGINE 是一个必须在模糊器构建的链接步骤中使用的标志。
$CC $CFLAGS char_lib.c -c -o char_lib.o
$CC $CFLAGS fuzz_char_lib.c -c -o fuzz_char_lib.o
$CC $LIB_FUZZING_ENGINE fuzz_char_lib.o char_lib.o -o $OUT/simple-fuzzer
OSS-Fuzz 运行时环境不从容器内运行模糊器,因此,二进制文件必须静态链接到其大多数依赖项。构建脚本必须将模糊测试二进制文件放在由 OUT 环境变量定义的目录中。
将这三个脚本放在 OSS-Fuzz 存储库中 projects
文件夹内的名为 oss-fuzz-example
的文件夹中,然后您就可以测试 OSS-Fuzz 集成了。
测试 OSS-Fuzz 集成
要测试 OSS-Fuzz 集成,请使用 OSS-Fuzz 存储库中的 infra/helper.py
脚本。此脚本接受各种命令。此示例最重要的命令是 build_fuzzers
、run_fuzzer
和 check_build
。这些命令是您测试集成所需的一切。
这些命令执行以下操作
build_fuzzers
构建项目的必要容器,并从这些容器内运行build.sh
脚本。run_fuzzer
为给定项目运行给定的模糊器。此命令必须在build_fuzzers
之后运行。check_build
执行各种检查以确保设置正常工作。必须通过此检查才能使 OSS-Fuzz 的 CI 成功。
可视化这些命令的最佳方法是按顺序运行它们。
首先,克隆两个存储库
$ git clone https://github.com/AdaLogics/oss-fuzz-example
$ git clone https://github.com/google/oss-fuzz
接下来,在 OSS-Fuzz 存储库中创建一个项目目录
$ mkdir oss-fuzz/projects/oss-fuzz-example
将 OSS-Fuzz 工件复制到目录
$ cp oss-fuzz-example/oss-fuzz-example/Dockerfile oss-fuzz/projects/oss-fuzz-example/Dockerfile
$ cp oss-fuzz-example/oss-fuzz-example/build.sh oss-fuzz/projects/oss-fuzz-example/build.sh
$ cp oss-fuzz-example/oss-fuzz-example/project.yaml oss-fuzz/projects/oss-fuzz-example/project.yaml
然后导航到 OSS-Fuzz 并构建模糊器
$ cd oss-fuzz
$ python3 infra/helper.py build_fuzzers oss-fuzz-example
现在运行模糊器。使用 CTRL+C 退出此步骤
$ python3 infra/helper.py run_fuzzer oss-fuzz-example simple-fuzzer
检查构建
$ python3 infra/helper.py check_build oss-fuzz-example
…
…
INFO:root:Check build passed.
提交 OSS-Fuzz 集成
在此阶段,您拥有集成所需的所有工件。完成集成之前的剩余步骤是在 OSS-Fuzz 存储库上创建一个包含 OSS-Fuzz 工件的拉取请求;具体来说,是 Dockerfile
、build.sh
和 project.yaml
文件。
如果维护者批准该拉取请求,则集成完成,OSS-Fuzz 开始持续运行模糊器。它会在仪表板上报告进度。此外,如果 OSS-Fuzz 在您的库中发现错误,它会向 project.yaml
文件的 primary_contact 和 auto_ccs 字段中的维护者列表发送详细报告,例如,堆栈跟踪和发现的问题。
模糊测试的重要性
概念验证集成是一个最小的示例。更复杂的项目可能难以配置模糊测试,但持续模糊测试会随着时间的推移带来回报。
项目应该与 OSS-Fuzz 集成的原因有很多。它是一项免费服务,背后有强大的支持,许多项目从中受益匪浅。截至 2022 年 1 月,OSS-Fuzz 已在550 个开源项目中发现了超过 36,000 个错误。
将模糊测试集成到项目中非常耗时。准备好为此投入精力,并且不要期望成熟的集成在一夜之间发生。许多项目已从模糊测试和 OSS-Fuzz 中受益,但大多数项目都投入了大量时间来确保集成和模糊测试设置良好运行。这很辛苦,但非常值得。
祝您 OSS-Fuzz 集成顺利,祝您 bug 狩猎愉快!
评论已关闭。