RFC-0117:组件模糊测试框架 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 一个 Fuchsia 原生的跨进程模糊测试框架。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2021-05-24 |
审核日期(年-月-日) | 2021-07-28 |
摘要
引导式模糊测试可有效减少错误并增加 对平台有信心,但目前还没有提供模糊测试框架 可以跨多个进程边界进行模糊测试(如 Fuchsia 中) 组件拓扑本文档针对此类 框架,可跨流程共享覆盖率和测试输入 以及在测试领域内进行,允许组件在其最主要的 典型配置
设计初衷
程序测试可用于显示是否存在 bug,但绝不能显示 他们的失踪!
引导式模糊测试是指在反馈环中测试软件的过程, 生成的数据:
- 模糊测试工具生成一些测试输入数据,并使用这些数据来测试 target 软件进行比较。
- 如果测试结果失败,模糊测试工具会记录输入并退出。
- 目标软件会生成由模糊测试工具收集的反馈。
- 模糊测试工具根据反馈生成其他测试输入,并重复该输入。
引导式模糊测试对于查找 与项目要求无关(因此通常未经测试)。通过自动 测试覆盖率,还可以提高开发者的关键部分置信度 系统的安全性、正确性和/或稳定性 注意事项。
可以使用以下分类来描述引导式模糊测试框架:
- 引擎:与目标无关的反馈环。
- 语料库管理:维护一系列模糊输入(
corpus)。记录新的输入并修改现有输入(例如合并)。
- 种子语料库是一组精心设计的初始输入。
- 实时语料库是一组持续更新的生成输入。
- Mutators:一组变更策略和确定性来源 用于从语料库创建新输入的伪随机性。
- 反馈分析:根据反馈处理意见。
- 管理界面:与用户互动以协调工作流:
<ph type="x-smartling-placeholder">
- </ph>
- 使用特定输入来练习目标,即执行一次 模糊测试工具运行。
- 对目标进行模糊测试,即执行一系列(可能是不确定的) 模糊测试工具运行。
- 分析或操纵给定语料库。
- 响应检测到的错误和/或处理 引发了该错误。
- 语料库管理:维护一系列模糊输入(
corpus)。记录新的输入并修改现有输入(例如合并)。
- 目标:进行模糊测试的具体目标领域。
- 输入处理:将单次运行的模糊测试工具输入映射到代码 被测数据,例如例如通过特定函数、I/O 管道等
- 反馈收集:观察输入导致的行为。5 月 收集硬件或软件跟踪记录、代码覆盖率数据、时间等。
- 错误检测:确定输入何时导致了错误。收集 并记录测试工件,例如包括输入、日志、回溯等。
其中一些方面可能需要操作系统和/或其 工具链,例如反馈收集和错误检测。目前已开启 Fuchsia,最完全受支持的模糊测试框架是 libFuzzer, 通过预构建的 clang 工具链提供,作为 编译器运行时。我们已向 sanitizer_common 运行时,用于收集代码覆盖率反馈,以及 libFuzzer 本身来检测异常。以及一组 GN 模板和托管工具,让开发者能够快速 为 Fuchsia 上的库开发模糊测试工具。
但与 Linux 不同的是,在 Fuchsia 上,软件的基本可执行单元 组件,而不是库。使用现有的引导式模糊测试框架进行模糊测试 会很麻烦,因为其反馈的粒度 过窄(例如单个进程中的 libFuzzer)或过于宽泛(例如 在 qemu 实例上使用 TriforceAFL)。
在 Fuchsia 中,用于模糊测试组件的理想框架具有以下特性:
- 与现有持续模糊测试基础架构集成,例如 ClusterFuzz。
- 一种模块化方法,可利用其他平台中与平台无关的部分 模糊测试框架,例如变更策略。
- 高性能的跨进程代码覆盖机制。
- 与现有 Fuchsia 工作流集成,例如
ffx
。 - 可以隔离被测组件和/或 为其依赖项提供模拟组件。
- 未修改的目标组件源。
- 一种可靠而灵活的方法来分析执行情况和检测错误。
- 一个类似于 Fuchsia 中其他测试类型的开发者故事。
设计
此设计试图:
- 遵循 Fuchsia 的习惯。
- 重复使用现有实现方案。
概括来讲,该设计利用了测试运行程序框架,并添加了:
- 用于驱动模糊测试的
fuzzer_engine
。 ffx
插件和模糊测试管理器,用于与模糊测试工具进行交互和管理模糊测试工具。- 一个
fuzz_test_runner
,用于将fuzzer_engine
连接到模糊测试管理器。
本文档的这一部分大致按照控制流进行组织: 也就是说,它从想要执行模糊测试任务的人或机器人开始, 对目标领域进行模糊测试。读者应该知道 部分会参考后续部分将详细介绍的概念。
ffx fuzz
托管工具
用户(真人和机器人)通过
ffx
插件。此插件将能与
通过以下方式提供 fuzz_manager
服务:
ffx fuzz
的子命令会镜像 fx fuzz
的子命令,例如:
analyze
:报告给定语料库和/或字典的覆盖率信息。check
:检查一个或多个模糊测试工具的状态。coverage
:为测试生成覆盖率报告。list
:列出当前 build 中可用的模糊测试工具。repro
:通过重放测试单元来重现模糊测试工具的发现结果。start
:启动特定的模糊测试工具。stop
:停止特定的模糊测试工具。update
:更新模糊测试工具语料库的 BUILD.gn 文件。
模糊测试管理器
测试运行程序框架提供两个重要功能:
- 它可让您轻松创建复杂但封闭的测试领域并推动这些领域 以及可自定义的测试运行程序。
- 它提供了收集重要诊断信息(例如日志和 回溯。
此外,一次模糊测试运行可以用以下术语自然地表示: 组件测试框架:使用指定的测试输入执行代码; 根据错误类型、 错误。
不过,模糊测试与其他形式的测试不同, 比较连续模糊和连续模糊 测试:
- 测试输入事先未知。
- 测试输入通过模糊测试生成。
- 持续模糊测试基础架构(如 ClusterFuzz)将具有 并会“交叉花粉”他们的测试输入 在进行模糊测试时运行。
- 模糊测试执行是开放式的。模糊测试从来不会真正“通过”,
失败或提前停止。
- 因此,需要提供包含详细信息的按需状态 通常不会由其他测试提供,例如执行速度、总 收集的反馈、使用的内存等
- 需要持续向真人或模糊测试工具提供此状态 用于监控模糊测试工具执行的基础设施机器人。
- 模糊测试结果比简单的通过/失败更丰富。
- 失败时,输出需要包含触发输入以及任何 关联的日志和回溯。
- 提前终止服务时,输出内容可能包括累计反馈和 建议的参数(例如字典)。
- 模糊测试领域可用于模糊测试 基础架构选择连续执行,例如“模糊一会儿。如果 发现错误,对其进行清理,否则,合并并压缩语料库”。 将每个步骤表示为测试套件可以提取大量工作 一个步骤就能恢复状态,以便在下一步骤中恢复。
其中一些问题可以通过扩展测试运行程序框架来解决,例如它
可以提供结构化输出。不过,如果使用该方法,
模糊测试需求会为其他不需要测试的
。因此,该设计添加了一个新的 fuzz_manager
,它具有以下特点:
- 通过
ffx
为用户提供管理界面。 - 与
test_manager
交互,以在 测试运行程序框架。 - 提供
fuchsia.fuzzer.manager.Harness
,以便这些模糊测试工具 重新连接并为用户请求提供服务。 - 提供数据传输协议,以方便将数据注入或 如何从模糊测试工具中提取数据。
然后,对测试运行程序框架进行修改,如下所示:
- 添加了新的
fuzz_test_runner
。此运行程序基于现有的elf_test_runner
用于启动fuzzer_engine
并向其传递模糊测试工具网址。 test_manager
已修改为路由fuzz_test_runner
的fuchsia.fuzzer.manager.Harness
功能。 此功能不会发送给测试,且非模糊测试工具的封闭性 不受影响。fuzz_test_runner
会为fuchsia.fuzzer.Controller
协议。它会将一端安装为初创公司fuzzer_engine
中的句柄,并使用fuchsia.fuzzer.manager.Harness
将另一个传递给fuzz_manager
。
模糊测试引擎
fuzzer_engine
是模糊测试领域的一个组件。对于
模糊测试工具分类,它能够:
- 实现
fuchsia.fuzzer.Controller
协议以提供 管理界面。 - 创建并使用存储空间功能来管理每个语料库。
- 对来自语料库的输入执行 Mutate 操作,以创建新的测试输入。(例如,链接 针对 libMutagen)。
Uses
是Adapter
的一项功能,用于发送要处理的新输入。Exposes
一项用于对遥控器进行插桩的fuchsia.fuzzer.ProcessProxy
capability 模糊领域的进程可以用于提供收集的反馈,并 报告错误。- 分析反馈。
如果将模糊测试视为具有不同输入的一系列测试,则 让模糊测试引擎为每个项目实例化一个全新的测试领域 输入,即让测试运行程序连续执行每个模糊测试运行。通过 这种方法的主要问题在于 和变更循环。模糊测试工具的质量与吞吐量直接相关, 必须极快地完成“mutate”、“处理输入、 反馈和分析反馈意见”应约为微秒级。
因此,模糊测试引擎包含在测试领域本身的 方式与用于测试复杂拓扑的测试驱动程序类似。 由事件对协调的共享 VMO 用于转移测试 模糊测试目标适配器输入输出,以及来自 对远程进程进行插桩,从而尽可能缩短延迟时间。
模糊测试工具引擎由 fuzz_test_runner
启动。这位跑步者非常
类似于现有的 elf_test_runner
,但添加了一项重要功能:
它会为 fuchsia.fuzzer.Controller
协议创建一个通道对。它
将此对的一端作为启动句柄安装在 fuzzer_engine
中。它
使用 fuchsia.fuzz.manager.Harness
将另一个代码传递给 fuzz_manager
功能由 test_manager
传送给它。这样一来,test_manager
便可以
仅向 fuzz_test_runner
和模糊测试工具提供 Harness
功能
而不是所有测试。
目标适配器
模糊测试目标适配器在 模糊测试工具分类。使用上述共享 VMO 和事件对, 获取由模糊测试引擎生成的测试输入, 与目标领域的插桩远程进程交互 生成模糊测试。
这些特定的交互由模糊测试工具作者提供, 这种贡献通常称为“编写模糊测试工具”。
模糊测试工具作者可以提供自己的模糊测试目标自定义实现 或使用所提供的某个 Scaffold。
可能的适配器基架示例包括:
llvm_fuzzer_adapter
:希望作者实现 LLVM 的 模糊测试目标函数。- 对于 C/C++,作者实现了:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
- 对于 Rust,作者使用
#[fuzz]
proc_macro
属性实现了一个方法。 - 对于 Go,作者实现了:
func Fuzz(s []byte);
realm_builder_adapter
:除了 LLVM 模糊测试目标函数之外, 作者会实现一个方法来修改所提供的RealmBuilder
。通过 适配器会为此函数提供默认构建器,并使用结果 构建要进行模糊测试的组件领域。作者可以通过将 其他路线、功能、模拟等:pub trait FuzzedRealmBuilder { fn extend(builder : &mut RealmBuilder); }
libfuzzer_adapter
:与llvm_fuzzer_adapter
的预期类似,但 组件清单省略了模糊测试引擎,并提供Controller
功能本身,并直接链接到 libFuzzer。这个 明显不同的组件拓扑支持传统的库模糊测试 libFuzzer 进行了测试。honggfuzz-persistent-adapter
:要求模糊测试工具作者实现:extern HF_ITER(uint8_t** buf, size_t* len);
honggfuzz
本身目前不受支持,但模糊测试目标 为其编写的函数仍然可以与此框架集成。
请注意,目标适配器可以并且也应该链接到远程库 并充当插桩远程进程与插桩测试中的进程一起运行 目标。
插桩远程进程
为了收集反馈和检测错误,目标范围内的所有流程
需要进行模糊测试的领域需要通过其他插桩(例如
SanitizerCoverage)。对于树内构建的模糊测试工具,可以通过
工具链变体,用于将 flags
和 deps
传播到 GN 目标的
依赖项必需的标志,例如-fsanitize-coverage=inline-8bit-counters
,
也会进行记录,以便允许树外编译。
此外,进程还需要一个 fuchsia.fuzzer.ProcessProxy
客户端
实施。上述工具链变体
将树内模糊测试工具的进程与远程库相关联的依赖项。
远程库根据模糊分类法提供:
- 通过回调收集反馈,例如
__sanitizer_cov_inline_8bit_counters_init
。 - 启动早期与
fuzzer_engine
的ProcessProxy
的连接。 - 可以检测错误的后台线程,例如监控异常 内存用量等
树外模糊测试工具可以提供自己的客户端实现。将
fuchsia.fuzzer.ProcessProxy
FIDL 接口和远程库实现
有助于更轻松地编写树外模糊测试工具。
最后,所需的编译时修改只是 LLVM 上的转换 IR。所有其他修改都仅在链接时生效。这样一来,服务提供商 提供“模糊测试即服务”愿意提供 LLVM 字节码用于其组件,而无需源代码。
组件拓扑
综上所述,模糊测试工具组件拓扑包括:
core
:系统根组件。fuzz_manager
:这是模糊测试工具与主机工具之间的根领域中的桥梁。test_manager
:与测试运行程序框架一样。target_fuzzer
:模糊领域入口点。fuzzer_engine
:与目标无关的模糊测试驱动程序。target_adapter
:包含用户提供输入的目标特定组件 处理代码。instrumented_target
:对组件进行模糊测试。
adapter
和 target
组件可能有其他子组件,例如
模拟和目标领域模糊不清。
上述各个部分的交互可如下所示:
FIDL 接口
该框架添加了两个 FIDL 库:一个用于
fuzz_manager
,另一个用于与模糊测试工具本身进行交互。
fuchsia.fuzzer.manager
fuchsia.fuzzer.manager
定义的类型包括:
LaunchError
:一个可扩展的enum
,列出与发现结果和 启动模糊测试工具
fuchsia.fuzzer.manager
定义的协议包括:
fuchsia.fuzzer.manager.Coordinator
:由fuzz_manager
通过以下服务向用户投放:ffx
。它包含启动模糊测试工具并将fuchsia.fuzzer.Controller
以及停止模糊测试工具的方法。fuchsia.fuzzer.manager.Harness
:由fuzz_manager
投放到fuzz_test_runner
(通过core
和test_manager
的静态路由)。通过 运行程序使用此协议将通道的一端传递给可 用于fuchsia.fuzzer.Controller
协议。
fuchsia.fuzzer
fuchsia.fuzzer
定义的类型包括:
Options
:带有用于配置执行的参数的可扩展table
,错误 检测等Feedback
:一个灵活的union
,表示目标反馈,例如代码 覆盖率、跟踪记录、时间等Status
:具有各种模糊指标的可扩展table
,例如总计 例如:覆盖范围、速度等,FuzzerError
:一个可扩展的enum
,列出错误类别,例如这些 ClusterFuzz 可以识别的特征。
fuchsia.fuzzer
定义的协议包括:
fuchsia.fuzzer.Controller
:由fuzzer_engine
提供并传递给 通过fuzz_test_runner
与fuzz_manager
通信。由fuzz_manager
代理 。包括将输入转移到/从 以及使用模糊测试工具执行工作流,例如输入最小化、语料库 合并和常规模糊测试fuchsia.fuzzer.CorpusReader
:已请求fuchsia.fuzzer.Controller
付款。 用于从特定种子或活动语料库获取输入。fuchsia.fuzzer.CorpusWriter
:已请求fuchsia.fuzzer.Controller
付款。 用于将输入添加到特定种子或活动语料库。fuchsia.fuzzer.Adapter
:由fuzzer_engine
开发者提供的target_adapter
。它包含用于注册 协调事件对和用于发送测试输入的共享 VMO。fuchsia.fuzzer.ProcessProxy
:由fuzzer_engine
向每个 插桩处理流程。包括用于注册 协调事件对,并注册用于提供反馈的共享 VMO。
构建实用程序
该框架为开发者提供了一个 fuchsia_fuzzer_package
GN 模板。
这使得他们可以:
- 自动包含 fuzzer_engine。
- 生成可供工具使用的元数据,例如种子的位置 语料库。
- 使用非模糊测试工具链时,构建集成测试,而不是模糊测试工具 选择变体,如测试部分中所述。
- 重复使用相关集成中被测组件的 build 规则 测试。
该框架还包含一个组件清单分片,其中包含
模糊测试工具所需的常见元素,例如fuzzer_engine
及其
fuzz_test_runner
等。模糊测试工具的组件清单
包括:
- 默认模糊测试工具分片。
- 指向目标适配器组件的网址。
- 要进行模糊测试的组件清单的网址。这通常应为 可在相关集成测试中重复使用。
结合使用这些构建实用程序,
类似于集成测试开发。
比较:
实现
实施计划很简单:单独进行开发和单元测试 类,然后组建从 libFuzzer,如测试部分所述。
语言
fuzzer_engine
和 remote_library
是用 C++ 实现的,
各自的特点:
fuzzer_engine
和remote_library
都必须与其他 C 集成 ABI,例如libMutagen、SanitizerCoverage 等- 大多数
remote_library
功能都发生在“main
之前和exit
之后”, 即,在构建和/或加载 LLVM 模块时,如果atexit
或发生严重异常时抛出该异常。因此, 框架需要明确控制 ELF 可执行文件的细微细节 生命周期
其他部分,例如realm_builder_adapter
是用 Rust 编写的。
数据传输协议
在某些情况下,用户需要提供或 检索任意数量的数据,包括:
- 提供要执行、清理或最小化的特定测试输入。
- 将模糊测试工具语料库与开发者主机上的,或在多个 ClusterFuzz 实例。
- 提取触发了错误的测试输入。
为了尽量减少维护负担,最好使用
overnet。不过,任何单次传输都可能会超出
一条 FIDL 消息。相反,Controller
协议包含多个方法,这些方法提供 zx_socket
对象,
模糊测试工具引擎用于将数据流式传输到 VMO 和/或本地存储的文件或从其流式传输数据。
使用最小协议流式传输数据,以读取或写入命名序列 字节。该协议不是 FIDL,因为发送的数据可能会超过 FIDL 消息的最大长度。命名的字节序列仍然是 在概念上等同于以下 FIDL 结构:
struct NamedByteSequence {
uint32 name_length;
uint32 size;
bytes:name_length name;
bytes:size data;
};
堆栈展开
目前,libFuzzer 使用 LLVM 中的展开程序,该展开程序假定从 在触发信号的线程上执行的 POSIX 信号处理程序。对于 Fuchsia,这就需要一种复杂的方法来处理 包括修改崩溃线程的堆栈和注入回溯- 保留汇编 trampoline 以“复活”展开程序中的线程
如果 libFuzzer 未处理错误,则无需执行以上任何操作。相反, 以最方便的方式处理不同类型的错误 有效,例如:
- 异常由模糊测试引擎处理,该引擎会接收 异常通道从其句柄 测试作业。
- 超时也由模糊测试工具引擎管理。
- Sanitizer 回调和 OOM 由远程库处理,该库会通知 模糊测试引擎
性能
模糊测试不对生产系统执行,因此对 以便了解任何配送代码的效果加入模糊测试工具链 变体对构建 Fuchsia 的性能影响很小, 框架会重复使用现有的变体,应该不会增加新的影响。
同样,在未插桩 build 上,通过模糊测试工具生成单元测试 反映当前方法,预计不会增加任何 当前方法的模糊测试工具测试成本。
对于模糊测试工具本身而言,决定模糊测试工具的最关键指标 质量是指每单位时间的覆盖率,可通过衡量 其他指标:
- 在固定时间段内运行的模糊测试工具的总覆盖率。
- 在固定时间段内执行的运行总次数。
ClusterFuzz 已针对每个模糊测试工具监控和发布这些指标 。
工效学设计
人体工学是该设计的一个重要方面,因为其影响取决于 提高 20%。
此框架尝试通过多种方式尽可能简化模糊测试。它 可让开发者:
- 使用熟悉和灵活的方式编写模糊测试工具,如 目标适配器部分。
- 使用现有的 GN 模糊测试模板系列构建模糊测试工具。
- 使用熟悉的工作流运行模糊测试工具。对
ffx fuzz
的使用是有意为之 类似于fx fuzz
。 - 获取切实可行的结果。通过与 ClusterFuzz 集成,用户会提交错误 自动添加符号化回溯和重现指令。
向后兼容性
基于 libFuzzer 的现有模糊测试工具会实现模糊测试目标函数。修改者 提供了特定于 libFuzzer 的模糊测试目标适配器,这些模糊测试工具将 无需修改源代码即可在此框架中运行。
安全注意事项
此框架不用于配送商品配置。对于设备
内置模糊测试配置,与设备的通信将使用
Google 提供的现有身份验证和安全通信功能
overnet
和 ffx
。
模糊测试工具输出可能需要考虑安全注意事项,例如,测试输入可能会导致 以及利用可利用的内存损坏这些问题必须由模糊测试工具处理 操作员(人工或模糊测试基础设施), 可利用的 bug 报告(例如正确标记、防止未经授权的人员) 披露声明等)。
隐私注意事项
在考虑隐私保护的影响时,对于 模糊测试工具运算符处理模糊测试工具输出。这些输出包括 日志、导致错误的输入、生成的字典和生成的语料库。 我们假定这些日志已不含用户数据,因为这是一个单独的 并密切监控隐私问题。其余输出则直接 这些特征从测试输入中衍生而来。因此,使模糊测试工具输入不含用户数据 确保模糊测试输出中不含用户数据。
您可以通过以下三种方式将输入添加到模糊测试工具的语料库中:
- 作为种子输入。种子语料库应签入源代码库。 针对在源代码库中包含用户数据的常见限制 。
- 作为对当前语料库的手动添加的内容。
- 这通常由模糊测试基础架构完成,例如 ClusterFuzz,因为它会“交叉授粉”将模型的输入 其他实例。在这种情况下,其他实例不会包含用户 而添加的输入则也不会。
- 人工操作员也可以通过
ffx
添加输入。 在以下位置添加手动输入时,该工具会显示有关用户数据的警告 。
- 作为实时语料库生成的新增内容。这些输入从 现有输入。由于这些输入是无用户数据的,因此生成的 。某些输入可能纯粹出于偶然因素而与某些用户数据匹配, 例如模糊测试工具设法生成有效的用户名。不过,在此示例中, 与用户数据之间没有明确关联。
语料库中不会包含任何其他数据,即使模糊测试工具是非封闭的(并且 具有不确定性!),并使用由测试领域公开的来源提供的数据。通过 框架不会将该数据视为测试输入的一部分,也不会 保存。
最糟糕的情况是使用模糊测试工具, 非封闭的,并且使用公开的功能将数据发送到测试领域 验证个人身份信息的其他服务返回用户名是否 有效。这需要付出大量的努力来规避 模糊测试和测试框架尝试促进封闭性。而且,由于 外部服务未进行插桩,这与随机猜测并无二致。
此外,在实践中,模糊测试工具将是完全封闭的。它们不会 可以在包含用户数据的产品配置上运行, 开发模糊测试工具以及 ClusterFuzz
测试
模糊测试工具引擎、目标适配器库和远程库是
使用常规方法(例如 GoogleTest、#[cfg(test)]
、
等)。此外,集成测试使用默认的 ELF 测试运行程序来运行
一组具有专门构建的示例目标的模糊测试工作流,基于
compile-rt 中的适用子集。
对于使用框架编写的模糊测试工具,框架将采用相同的 方法:构建 未插桩 build 中使用模糊测试工具,则引擎将被测试所取代 驱动程序,只执行种子语料库中的每个输入。这样可以缓解 “bit-rot”确保所有模糊测试工具都可以构建和运行。它还起着 回归测试,尤其是在模糊测试工具作者通过 在修复通过模糊测试发现的缺陷时添加输入。
文档
模糊测试文档树需要使用特定的 新 GN 模板使用示例。计划的任何其他文档更改 (例如 Codelab 等)也应反映此框架。
缺点和替代方案
所提方法的潜在缺点包括:
- 性能下降的风险,可通过实现密切降低 模仿高度优化的模糊测试工具中对性能至关重要的部分。
- 维护负担,但因无需维护而节省了费用 尴尬的集成,如POSIX 模拟。
- 耦合风险,例如测试运行程序框架可能会
或由于该设计而无法这样做。如果
这就会成为一个问题,可以加入
将
test_manager
的更多功能直接导入fuzz_manager
,例如拥有 后者会直接创建独立的测试领域。
这些缺点不像其他替代方案那样重要 包括:
仅使用 libFuzzer 进行库模糊测试。
libFuzzer 中已添加了足够的 Fuchsia 支持,以便使用它来构建模糊测试工具 在 Fuchsia 上。他们已经在 。
同时,它们仅限于结构为库的单个进程。 由于组件是 Fuchsia 上可执行软件的单元,而组件 进行广泛沟通,这使得 Fuchsia 代码“unfuzzable”模型。
进程内 FIDL 模糊测试。
Chrome 等项目已尝试通过运行客户端和 服务器线程。这需要修改客户端和 以新的非标准配置运行。它可以在两个 Pod 之间 但往往倾向于对组件生命周期做出不灵活的假设 和/或按语言绑定重新实现。
从本质上讲,对 交互组件。许多组件都有一个非常重要的拓扑。更改为 或模拟整个封路的方式 提高复杂性、开销和性能
此方法已在 Fuchsia 上推出,但尚未出现 得到广泛采用,至少在一定程度上是由于这些限制。
单服务 FIDL 模糊测试。
初步尝试设计跨进程 FIDL 模糊测试框架 视为单个客户端和服务在此设计中,libFuzzer 并且客户端作为简单代理进行维护。修改者 保留客户端和服务器之间的 FIDL 接口,就可以将 目标,从而提供更灵活的服务 因而需要重新实现的代码更少。
不过,这种方法并不能解决模糊组件闭包问题,并且 因此与进程内 FIDL 模糊测试相比,优势非常有限。
支持跨进程模糊测试的 LibFuzzer。
一般来说,与重新实现代码相比,重复使用代码具有多项优势,
代码通常更“成熟”,性能更好,错误更少,
而且维护费用较低出于这些原因,
试图扩展 libFuzzer,而不是设计和实现新的
模糊测试框架新的编译器运行时 clang_rt.fuzzer-remote.a
将执行
如上面的远程库一样,而 libFuzzer 本身可以用作引擎。
这两个编译器运行时都会使用一对特定于操作系统的 IPC 传输
来代理对其他进程的方法调用。
与 libFuzzer 的维护人员协调,实施了一系列更改 并发布它们以供审核。此外, IPC 传输库的实现是针对 Linux 和 紫红色。维护人员明确请求获得 Linux 支持, 持续测试,并会再次送交审核。
- 在 Linux 上,共享内存创建为匿名映射文件,即
通过
memfd_create
发送,信号就是通过 Unix 传递的消息。 域套接字。这些套接字还用于传输共享内存 文件描述符,即通过sendmsg
和recvmsg
。 - 在 Fuchsia 上,共享内存使用 VMO 实现,通过 事件对,并通过 FIDL 消息进行交换,方式与 此提案中的设计
遗憾的是,经过大量审核,这种方法不可行, 但出于技术原因:随着时间的推移,libFuzzer 维护人员 越来越多地担心必要的更改, 使 libFuzzer 无法以其最初设计的方式运作。最终, 团队决定无限期推迟提交所提议的更改。
澳式足球联赛
LibFuzzer 绝不是唯一的模糊测试框架。有些技术(如 AFL) 从一开始就明确设计为跨进程。不过, 一些原因在于 AFL 需要比其他情况更多的投资:
- AFL 假定它对单个进程进行模糊测试,因此仍然面临闭包问题 问题。
- AFL 大量使用某些 Linux 和/或 POSIX 功能来获取反馈和
错误检测。其中包括 POSIX 信号,但更重要的是,
大量使用了
/proc
文件系统,而实际上没有 紫红色的模拟 - AFL 使用经过修改的 GCC 对代码进行插桩,但后者不属于 Fuchsia 的 工具链。
AFLplusplus 是经过改进的 AFL 分支,由一套安全体系维护 和 CTF 竞争对手。在 FuzzBench,并采用了模块化的 AFL。遗憾的是, 第一个版本已弃用,而第二个版本尚未准备就绪(或者, 至少不够成熟,无法强制更改上述设计)。不过, 有几个方面与此提案的设计是一致的, 来提升框架的覆盖率、速度或 两者都有。
AFL 和 qemu
此外,还有几个项目将 AFL 与 qemu 结合使用:
- afl-unicorn 将 AFL 与 Unicorn 相结合,后者是一个公开
qemu 的 CPU 模拟核心,具有相当简洁的接口。这样,
通过从 Android 设备收集覆盖率反馈,对无源代码的不透明二进制文件进行模糊测试
CPU 模拟它不适合少数应用的组件框架,
原因:
<ph type="x-smartling-placeholder">
- </ph>
- 与 qemu 的核心 CPU 模拟的集成非常复杂, Unicorn 决定放弃 qemu 的开发, v2.1.2(与当前版本的 qemu 6.0.0 相比)。需要 较新的模拟功能不太可能正常运行。
- 没有明显的不透明二进制模糊测试需求。事实上,设计上 只需要对目标代码进行插桩,并关联到 远程库;LLVM 字节码足以实现这一点。
- TriforceAFL 在完整的插桩 qemu 实例上使用 AFL。这个
再次允许对无源代码的不透明二进制文件进行模糊测试,方法是收集覆盖率信息
来自 QEMU 本身它不适用于与 afl-unicorn 类似的原因:
<ph type="x-smartling-placeholder">
- </ph>
- 同样,对不透明二进制模糊测试没有明显的需求。
- 此外,由于收集的覆盖率针对整个实例, 使用 TriforceAFL 进行模糊测试往往会产生很多噪声, 组件正在运行。它通常仅用于 受限的配置,例如启动后立即启动的 USB 驱动程序。