news 2026/9/16 16:31:44

使用 Fuzzilli 对 workerd 进行 JavaScript 模糊测试:REPRL 集成与配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Fuzzilli 对 workerd 进行 JavaScript 模糊测试:REPRL 集成与配置实战

使用 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 接入 workerd(Cloudflare Workers 的 JavaScript/Wasm 运行时),通过 REPRL(REad-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 平台 API(KV、D1、R2、Analytics、Queue)以及把 Node.js 模块暴露到全局作用域,供模糊测试脚本直接调用。

目录内文件均由 fuzzilli/BUILD.bazel 中的exports_files(glob(["*.capnp", "*.js"]))导出,因此这些配置和脚本可以被 Bazel 构建系统引用。核心文件对应关系如下:

文件角色
config.capnp基础 REPRL 配置,加载worker.js,仅含极简 binding
config-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.capnp":workerd 的 capnp 模式定义,Workerd.Config声明一个可运行的 workerd 实例,Workerd.Worker声明具体的 Worker。
  • services:声明服务main,其 Worker 指向下面的replServer
  • sockets:声明 HTTP 监听*:8080。注释# We don't 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 = 10maxValueSize = 1024maxTotalValueSize = 1024),用于让模糊测试脚本能够触达 cache 相关 API 路径。
  • compatibilityDate:配置兼容日期,基础版为2023-02-28,完整版已更新到2025-05-01
  • compatibilityFlags:启用nodejs_compat(Node.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-kvtest-d1-mocktest-r2test-analyticstest-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_modulehtml_rewriter_treats_esi_include_as_void_tagdurable_object_renameservice_binding_extra_handlersexpose_global_message_channelenable_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 全部挂到globalThis

  • Web 标准ResponseRequestHeadersURLURLPatternURLSearchParamsTextEncoder/Decoderatob/btoaBlobFileFormDatafetchWebSocketEventSourceHTMLRewriterMessageChannel/PortAbortController/Signal
  • 流 APIReadableStreamWritableStreamTransformStreamCompressionStreamDecompressionStreamTextEncoderStream/DecoderStreamIdentityTransformStreamFixedLengthStream
  • Node.js 模块node:fsnode:bufferBuffernode:stream的读写/转换流、node:string_decodernode:eventsnode:processenvnode:zlibnode:async_hooksAsyncLocalStoragenode:diagnostics_channelnode:dnsnode:pathnode:crypto
  • 测试与断言node:assertok/match/rejects/throws/strictEqual/deepStrictEqual/notStrictEqualnode:testmock,让模糊测试脚本可以直接书写断言;
  • Cloudflare API 内存 mockMOCK_KVMOCK_D1MOCK_R2,直接以 Promise 返回构造好的数据。

值得注意的细节:脚本显式执行process = undefined; globalThis.process = undefined;以移除 process 全局,模拟 Workers 运行时环境;同时把scheduler挂到globalThis.schedulerscheduler.await使用。这些 global 的暴露清单本身就是一份"当前已纳入模糊测试的 API 范围"索引——新增 API 时只需在test()中追加globalThis.xxx = xxx即可。

REPRL 协议原理:从握手到脚本执行

README 将 REPRL 主执行流程归纳为 5 个步骤,与源码 src/workerd/api/unsafe.c++ 中Stdin::reprl()(受#ifdef WORKERD_FUZZILLI保护,仅在 Fuzzilli 构建下编译)的实现完全对应:

  1. Fuzzilli 启动 workerd,并把要执行的测试脚本交给它;
  2. workerd 读取 capnp 配置,配置指向导入了自定义 API 端点的脚本(例如config.capnp+worker.js);
  3. workerd 导入依赖并调用Stdin.reprl()
  4. 握手阶段:workerd 打开管道与共享内存,向 Fuzzilli 写入 4 字节HELO,Fuzzilli 回写HELO(源码中write(REPRL_CWFD, helo, 4)read(REPRL_CRFD, helo, 4),并校验内容是否为"HELO");
  5. 执行循环: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 << 20(16 MB);32 位退出状态格式为[ did_timeout | exit_code | terminating_signal ],分别用RIFTIMEDOUTREXITSTATUSRTERMSIG提取。该库同时提供了reprl_initialize_contextreprl_executereprl_fetch_stdoutreprl_fetch_stderrreprl_fetch_fuzzout等接口,供测试程序驱动 workerd 子进程。

验证 REPRL 是否可用

1. Bazel 单元测试

README 给出第一条验证路径——运行仓库内自带的 REPRL 集成测试:

bazel test --config=fuzzilli //src/workerd/tests:test-reprl-kj --repo_env=CC=/usr/bin/clang-19 --test_timeout=5 --test_output=all
  • --config=fuzzilli:启用 Fuzzilli 专属构建配置(对应上面的WORKERD_FUZZILLI编译开关);
  • //src/workerd/tests:test-reprl-kj:目标测试,源码位于 src/workerd/tests/test-reprl.c++,在 src/workerd/tests/BUILD.bazel 中声明;
  • --repo_env=CC=/usr/bin/clang-19:指定 clang-19 作为编译器(SanitizerCoverage 与 Fuzzilli 通常依赖较新的 clang);
  • --test_timeout=5:测试超时 5 秒,--test_output=all打印完整输出。

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/workerd),fuzzilli为 profile 名称,第三个参数为 capnp 配置路径。REPRLRun会模拟 Fuzzilli 的 REPRL 驱动行为,向 workerd 发送脚本并检查返回状态,是确认"握手-执行-回报"链路是否打通的快速手段。

使用语料库进行大规模模糊测试

验证通过后即可启动正式模糊测试:

swift run -c release FuzzilliCli --inspect=all --profile=workerd <path-to-workerd-root>/bazel-bin/src/workerd/server/workerd --additionalArguments=<path-to-workerd-root>/samples/reprl/config-full.capnp,--experimental --storagePath=fs-new --jobs=30 --importCorpus=<path-to-corpus> --corpusImportMode=full --staticCorpus

参数逐一拆解:

  • swift run -c release:以 release 模式运行 FuzzilliCli,保证模糊测试吞吐;
  • --inspect=all:对所有匹配的 worker 进行状态检查与诊断输出;
  • --profile=workerd:使用 workerd profile(与上面的 REPRLRun 冒烟测试保持一致的 profile 名);
  • <path-to-workerd-root>/bazel-bin/src/workerd/server/workerd:被测试的 workerd 二进制路径;
  • --additionalArguments=<capnp 配置>,--experimental:追加传给 workerd 的命令行参数。注意:README 中此路径写作samples/reprl/config-full.capnp,但当前仓库中该配置实际位于 fuzzilli/config-full.capnp,使用时应替换为正确的仓库相对路径;
  • --storagePath=fs-new:Fuzzilli 状态存储目录,用于持久化语料库与崩溃样本;
  • --jobs=30:并发执行 30 个 workerd 实例,最大化吞吐;
  • --importCorpus=<path-to-corpus>+--corpusImportMode=full:全量导入已有语料库作为种子;
  • --staticCorpus:语料库按静态方式维护,配合fs-new存储路径实现可复现的模糊会话。

扩展测试范围:如何把新 API 纳入模糊测试

README 给出了明确的扩展路径:"要测试某个 API,把它 import 到所使用的.js文件中"。完整操作流程如下:

  1. 修改入口脚本:在 worker-full.js 顶部import目标 API(或内部模块),并在test()处理器中通过globalThis.xxx = xxx暴露到全局作用域,使 Fuzzilli 生成的脚本可以直接引用;
  2. 若涉及平台绑定:在 config-full.capnp 的bindings中新增对应 binding(如kvNamespacer2Bucketqueue),必要时同步新增 mock 服务与 mock 脚本,遵循现有test-kv/kv-mock.js的范式;
  3. 重新构建并冒烟测试:用bazel test --config=fuzzilli //src/workerd/tests:test-reprl-kjREPRLRun验证新 API 在 REPRL 模式下可用;
  4. 运行模糊测试:使用 FuzzilliCli 命令,观察新 API 路径上的覆盖率与崩溃样本。

相关源码与测试索引

  • 入口与配置:fuzzilli/config.capnp、fuzzilli/config-full.capnp、fuzzilli/worker.js、fuzzilli/worker-full.js
  • mock 实现:fuzzilli/kv-mock.js、fuzzilli/d1-mock.js、fuzzilli/r2-mock.js、fuzzilli/analytics-mock.js、fuzzilli/queue-mock.js、fuzzilli/worker-consume-request.js
  • REPRL 运行时实现:src/workerd/api/unsafe.c++(Stdin::reprl#ifdef WORKERD_FUZZILLI
  • REPRL 协议库:src/workerd/tests/libreprl/libreprl.h、src/workerd/tests/libreprl/libreprl.c
  • 集成测试:src/workerd/tests/test-reprl.c++、src/workerd/tests/BUILD.bazel
  • 内部平台 API(D1 包装的来源):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.jsconfig-full.capnp中按既有范式追加 API 与绑定,即可把新的运行时特性纳入自动化漏洞挖掘体系。

【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 16:30:49

嵌入式架构选型:MCU、MPU与SoC的边界与迁移实战

做嵌入式这些年&#xff0c;我最大的教训是&#xff1a;选 MCU、MPU 还是 SoC&#xff0c;千万别只盯着参数表。五年前做一款工业网关&#xff0c;当时团队最熟的平台是 STM32&#xff0c;方案评审阶段大家一致选 MCU 主控&#xff0c;理由很充分&#xff1a;便宜、功耗低、团队…

作者头像 李华
网站建设 2026/9/16 16:28:26

MyBatis多对一关系映射实战与优化

1. 项目概述在数据库设计中&#xff0c;多对一关系是最常见的数据关联方式之一。比如一个部门可以有多个员工&#xff0c;但每个员工只属于一个部门。这种关系在实际业务场景中无处不在&#xff0c;但在ORM框架中如何优雅地处理这种映射关系&#xff0c;一直是开发者需要面对的…

作者头像 李华
网站建设 2026/9/16 16:26:57

STM32F103红外循迹与超声波避障协同控制实战

简介&#xff1a;本资源是一套基于STM32F103微控制器的智能循迹避障小车完整工程代码与开发资料&#xff0c;面向嵌入式初学者、电子设计竞赛备赛学生及STM32实践开发者&#xff0c;解决智能小车自主导航、路径跟踪与动态避障的核心实现问题。压缩包共192个文件&#xff0c;含3…

作者头像 李华
网站建设 2026/9/16 16:24:23

PSO-BP神经网络回归预测:MATLAB实现与参数优化详解

简介&#xff1a;一个基于粒子群算法优化BP神经网络的MATLAB实现&#xff0c;面向算法学习者和人工智能开发者&#xff0c;专门针对MATLAB R2016a环境进行了适配。压缩包共收录3个文件&#xff0c;包含2个m脚本和1个mat数据文件&#xff0c;整体仅47KB&#xff0c;代码紧凑且结…

作者头像 李华