
使用 Fuzzilli 对 workerd 进行 JavaScript 模糊测试REPRL 集成与配置实战【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd导读本文基于 workerd 仓库中的 fuzzilli/README.md系统讲解如何将 Google 出品的 JavaScript 引擎模糊测试工具 Fuzzilli 接入 workerdCloudflare Workers 的 JavaScript/Wasm 运行时通过 REPRLREad-PRint-Loop读-执行循环协议批量执行由 Fuzzilli 生成的测试脚本从而发现 V8 引擎、内建 API 与 Node.js 兼容层中的崩溃与缺陷。读完本文你将掌握 fuzzilli 目录中 capnp 配置与 JS mock 的组织方式、REPRL 握手与执行协议的工作原理、验证 REPRL 接口是否可用的测试命令以及使用 FuzzilliCli 配合语料库进行大规模模糊测试的完整实战方案。目录结构与角色定位fuzzilli 目录是 workerd 为 Fuzzilli 模糊测试专门准备的接入层它并不包含模糊测试引擎本身而是提供两类关键资产capnp 配置声明 workerd 需要以何种 Worker 形态启动、加载哪个入口脚本、注入哪些 binding 与 compatibility flags用于在 REPRL 模式下把 workerd 变成一个一次启动、反复执行外部脚本的测试宿主。JavaScript mock 与入口脚本用于模拟 Cloudflare 平台 APIKV、D1、R2、Analytics、Queue以及把 Node.js 模块暴露到全局作用域供模糊测试脚本直接调用。目录内文件均由 fuzzilli/BUILD.bazel 中的exports_files(glob([*.capnp, *.js]))导出因此这些配置和脚本可以被 Bazel 构建系统引用。核心文件对应关系如下文件角色config.capnp基础 REPRL 配置加载worker.js仅含极简 bindingconfig-full.capnp完整 REPRL 配置加载worker-full.js注入服务绑定与多个 mock 服务worker.js基础入口仅导入workerd:stdin并调用Stdin.reprl()worker-full.js完整入口把 Web 标准、流、Node.js 模块与测试断言全部暴露到全局kv-mock.js / d1-mock.js / r2-mock.js / analytics-mock.js / queue-mock.js对应 Cloudflare 平台 API 的 mock 实现worker-consume-request.js供 service binding 消费请求的辅助 Worker基础 REPRL 配置config.capnp 逐段拆解基础配置 config.capnp 是理解整个接入流程的最小样例其结构如下using Workerd import /workerd/workerd.capnp; const reprl :Workerd.Config ( services [ (name main, worker .replServer) ], sockets [ ( name http, address *:8080, http (), service main ) ] ); const replServer :Workerd.Worker ( modules [ (name worker, esModule embed worker.js) ], bindings [ ( name secret, text thisisasecret ), ( name CACHE, memoryCache ( id abc123, limits ( maxKeys 10, maxValueSize 1024, maxTotalValueSize 1024, ), ) ) ], compatibilityDate 2023-02-28, compatibilityFlags [nodejs_compat, experimental, unsafe_module] );关键点说明using Workerd import /workerd/workerd.capnpworkerd 的 capnp 模式定义Workerd.Config声明一个可运行的 workerd 实例Workerd.Worker声明具体的 Worker。services声明服务main其 Worker 指向下面的replServer。sockets声明 HTTP 监听*:8080。注释# We dont need sockets for REPRL mode as it uses direct file descriptors见完整版配置明确指出REPRL 模式并不依赖 socket而是直接使用文件描述符通信因此完整版配置直接省略了 sockets 块。modules通过embed worker.js把入口脚本内嵌进二进制模块名worker即 REPRL 模式下的宿主脚本。bindings注入两个 binding——字符串类型的secret值为thisisasecret与内存缓存CACHEmaxKeys 10、maxValueSize 1024、maxTotalValueSize 1024用于让模糊测试脚本能够触达 cache 相关 API 路径。compatibilityDate配置兼容日期基础版为2023-02-28完整版已更新到2025-05-01。compatibilityFlags启用nodejs_compatNode.js 兼容层、experimental实验特性与unsafe_module允许导入内部模块如workerd:stdin。完整 REPRL 配置config-full.capnp 的 API 覆盖策略fuzzilli/config-full.capnp 是到目前被模糊测试过的 API 全集的配置README 明确要求若要测试某个 API把它导入到所使用的.js文件中。相比基础版它做了三件事的扩展1. 扩展 services为平台 API 提供 mock 后端除main外新增consumer消费请求以及test-kv、test-d1-mock、test-r2、test-analytics、test-queue五个 mock 服务分别对应 kv-mock.js、d1-mock.js、r2-mock.js、analytics-mock.js、queue-mock.js。2. 扩展 bindings注入全套 Cloudflare API 绑定bindings [ (name CONSUMER, service consumer), (name volatileCache, memoryCache ( id abc123, limits ( maxKeys 100, maxValueSize 1024, maxTotalValueSize 102400, ), )), (name MY_KV, kvNamespace test-kv), (name MY_D1, wrapped ( moduleName cloudflare-internal:d1-api, innerBindings [(name fetcher, service test-d1-mock)], )), (name MY_R2, r2Bucket test-r2), (name ANALYTICS, analyticsEngine test-analytics), (name MY_QUEUE, queue test-queue), ]注意 D1 使用wrapped方式包装内部模块cloudflare-internal:d1-api并通过innerBindings把 fetcher 指向 mock 服务——这与 src/cloudflare/internal/d1-api.ts 等内部 API 的注入方式一致。3. 扩展 compatibilityFlags在基础三项之上追加enable_nodejs_fs_module、html_rewriter_treats_esi_include_as_void_tag、durable_object_rename、service_binding_extra_handlers、expose_global_message_channel、enable_web_file_system尽量扩大 API 覆盖范围。以 kv-mock.js 为例mock 实现还注入了混沌行为约 12% 概率返回 429/503/408 状态码、畸形 JSON 或错误 Content-Type从而让模糊测试脚本也能覆盖错误处理与类型断言分支。Worker 入口脚本worker.js 与 worker-full.js基础入口 worker.js 极简到只有三行核心逻辑import { default as Stdin } from workerd:stdin; export default { async test() { Stdin.reprl(); }, };它通过unsafe_module兼容标志导入workerd:stdin在test()处理器中调用Stdin.reprl()进入 REPRL 主循环。完整入口 worker-full.js 则在进入 REPRL 循环前把待测 API 全部挂到globalThisWeb 标准Response、Request、Headers、URL、URLPattern、URLSearchParams、TextEncoder/Decoder、atob/btoa、Blob、File、FormData、fetch、WebSocket、EventSource、HTMLRewriter、MessageChannel/Port、AbortController/Signal流 APIReadableStream、WritableStream、TransformStream、CompressionStream、DecompressionStream、TextEncoderStream/DecoderStream、IdentityTransformStream、FixedLengthStreamNode.js 模块node:fs、node:buffer的Buffer、node:stream的读写/转换流、node:string_decoder、node:events、node:process的env、node:zlib、node:async_hooks的AsyncLocalStorage、node:diagnostics_channel、node:dns、node:path、node:crypto测试与断言node:assert的ok/match/rejects/throws/strictEqual/deepStrictEqual/notStrictEqual与node:test的mock让模糊测试脚本可以直接书写断言Cloudflare API 内存 mockMOCK_KV、MOCK_D1、MOCK_R2直接以 Promise 返回构造好的数据。值得注意的细节脚本显式执行process undefined; globalThis.process undefined;以移除 process 全局模拟 Workers 运行时环境同时把scheduler挂到globalThis.scheduler供scheduler.await使用。这些 global 的暴露清单本身就是一份当前已纳入模糊测试的 API 范围索引——新增 API 时只需在test()中追加globalThis.xxx xxx即可。REPRL 协议原理从握手到脚本执行README 将 REPRL 主执行流程归纳为 5 个步骤与源码 src/workerd/api/unsafe.c 中Stdin::reprl()受#ifdef WORKERD_FUZZILLI保护仅在 Fuzzilli 构建下编译的实现完全对应Fuzzilli 启动 workerd并把要执行的测试脚本交给它workerd 读取 capnp 配置配置指向导入了自定义 API 端点的脚本例如config.capnpworker.jsworkerd 导入依赖并调用Stdin.reprl()握手阶段workerd 打开管道与共享内存向 Fuzzilli 写入 4 字节HELOFuzzilli 回写HELO源码中write(REPRL_CWFD, helo, 4)与read(REPRL_CRFD, helo, 4)并校验内容是否为HELO执行循环Fuzzilli 发送exec命令action 值0x63657865随后发送 8 字节脚本长度再通过数据管道发送脚本本身workerd 以{ script }形式包装脚本kj::str({, script_, })用jsg::NonModuleScript::compile编译后在独立作用域内执行——与eval命令的语义类似。执行结果的处理逻辑同样清晰脚本正常执行完毕返回 0抛出JsExceptionThrown时返回 11对应退出码11 8写回状态管道每轮结束后调用__sanitizer_cov_reset_edgeguard重置 SanitizerCoverage 的边守卫计数器供 Fuzzilli 收集覆盖率反馈。REPRL 的协议规范来自 src/workerd/tests/libreprl/libreprl.h源自 V8 项目、Google 开源单次可传输脚本上限REPRL_MAX_DATA_SIZE 16 2016 MB32 位退出状态格式为[ did_timeout | exit_code | terminating_signal ]分别用RIFTIMEDOUT、REXITSTATUS、RTERMSIG提取。该库同时提供了reprl_initialize_context、reprl_execute、reprl_fetch_stdout、reprl_fetch_stderr、reprl_fetch_fuzzout等接口供测试程序驱动 workerd 子进程。验证 REPRL 是否可用1. Bazel 单元测试README 给出第一条验证路径——运行仓库内自带的 REPRL 集成测试bazel test --configfuzzilli //src/workerd/tests:test-reprl-kj --repo_envCC/usr/bin/clang-19 --test_timeout5 --test_outputall--configfuzzilli启用 Fuzzilli 专属构建配置对应上面的WORKERD_FUZZILLI编译开关//src/workerd/tests:test-reprl-kj目标测试源码位于 src/workerd/tests/test-reprl.c在 src/workerd/tests/BUILD.bazel 中声明--repo_envCC/usr/bin/clang-19指定 clang-19 作为编译器SanitizerCoverage 与 Fuzzilli 通常依赖较新的 clang--test_timeout5测试超时 5 秒--test_outputall打印完整输出。2. Fuzzilli 侧 REPRLRun 冒烟测试若已具备 Fuzzilli 工程Swift 编写在 Fuzzilli 目录下执行swift run REPRLRun path-to-workerd fuzzilli path-to-capnp-config --experimental其中path-to-workerd指向编译出的 workerd 二进制README 建议位于bazel-bin/src/workerd/server/workerdfuzzilli为 profile 名称第三个参数为 capnp 配置路径。REPRLRun会模拟 Fuzzilli 的 REPRL 驱动行为向 workerd 发送脚本并检查返回状态是确认握手-执行-回报链路是否打通的快速手段。使用语料库进行大规模模糊测试验证通过后即可启动正式模糊测试swift run -c release FuzzilliCli --inspectall --profileworkerd path-to-workerd-root/bazel-bin/src/workerd/server/workerd --additionalArgumentspath-to-workerd-root/samples/reprl/config-full.capnp,--experimental --storagePathfs-new --jobs30 --importCorpuspath-to-corpus --corpusImportModefull --staticCorpus参数逐一拆解swift run -c release以 release 模式运行 FuzzilliCli保证模糊测试吞吐--inspectall对所有匹配的 worker 进行状态检查与诊断输出--profileworkerd使用 workerd profile与上面的 REPRLRun 冒烟测试保持一致的 profile 名path-to-workerd-root/bazel-bin/src/workerd/server/workerd被测试的 workerd 二进制路径--additionalArgumentscapnp 配置,--experimental追加传给 workerd 的命令行参数。注意README 中此路径写作samples/reprl/config-full.capnp但当前仓库中该配置实际位于 fuzzilli/config-full.capnp使用时应替换为正确的仓库相对路径--storagePathfs-newFuzzilli 状态存储目录用于持久化语料库与崩溃样本--jobs30并发执行 30 个 workerd 实例最大化吞吐--importCorpuspath-to-corpus--corpusImportModefull全量导入已有语料库作为种子--staticCorpus语料库按静态方式维护配合fs-new存储路径实现可复现的模糊会话。扩展测试范围如何把新 API 纳入模糊测试README 给出了明确的扩展路径要测试某个 API把它 import 到所使用的.js文件中。完整操作流程如下修改入口脚本在 worker-full.js 顶部import目标 API或内部模块并在test()处理器中通过globalThis.xxx xxx暴露到全局作用域使 Fuzzilli 生成的脚本可以直接引用若涉及平台绑定在 config-full.capnp 的bindings中新增对应 binding如kvNamespace、r2Bucket、queue必要时同步新增 mock 服务与 mock 脚本遵循现有test-kv/kv-mock.js的范式重新构建并冒烟测试用bazel test --configfuzzilli //src/workerd/tests:test-reprl-kj与REPRLRun验证新 API 在 REPRL 模式下可用运行模糊测试使用 FuzzilliCli 命令观察新 API 路径上的覆盖率与崩溃样本。相关源码与测试索引入口与配置fuzzilli/config.capnp、fuzzilli/config-full.capnp、fuzzilli/worker.js、fuzzilli/worker-full.jsmock 实现fuzzilli/kv-mock.js、fuzzilli/d1-mock.js、fuzzilli/r2-mock.js、fuzzilli/analytics-mock.js、fuzzilli/queue-mock.js、fuzzilli/worker-consume-request.jsREPRL 运行时实现src/workerd/api/unsafe.cStdin::reprl#ifdef WORKERD_FUZZILLIREPRL 协议库src/workerd/tests/libreprl/libreprl.h、src/workerd/tests/libreprl/libreprl.c集成测试src/workerd/tests/test-reprl.c、src/workerd/tests/BUILD.bazel内部平台 APID1 包装的来源src/cloudflare/internal/d1-api.ts小结fuzzilli 目录为 workerd 提供了一条完整的引擎级模糊测试通道capnp 配置决定 Worker 形态与 binding 注入JS 入口脚本决定哪些 API 暴露给模糊器Stdin.reprl()通过 REPRL 协议与 Fuzzilli 完成握手、脚本收发与状态回报。借助test-reprl-kj集成测试与REPRLRun冒烟命令可以快速验证接入正确性而 FuzzilliCli 的--jobs、--importCorpus、--staticCorpus等参数则支撑起大规模、可复现的持续模糊测试流程。对于任何希望扩展模糊覆盖面的开发者而言只需在worker-full.js与config-full.capnp中按既有范式追加 API 与绑定即可把新的运行时特性纳入自动化漏洞挖掘体系。【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考