ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Skia 模糊测试(Fuzzing)体系解析:fuzz 可执行文件、API/Binary Fuzzer 与 OSS-Fuzz 集成指南

Skia 模糊测试(Fuzzing)体系解析:fuzz 可执行文件、API/Binary Fuzzer 与 OSS-Fuzz 集成指南 图形学图像处理【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images.项目地址https://gitcode.com/gh_mirrors/skia1/skia点击查看免费下载Skia 的fuzz/目录存放着项目全部模糊测试器fuzzer它们接收随机化输入定向驱动 Skia 的编解码器、画布绘制、SkSL 编译等特定 API用于在 CI 与 OSS-Fuzz 为骨架结合fuzz/源码与 BUILD.gn 构建定义完整梳理 Skia fuzzer 的两种打包形态、命令行用法、Fuzz 随机数据抽象、API/Binary fuzzer 的区分以及接入 OSS-Fuzz 的完整操作流程读完即可复现 fuzzer 报告的 bug或为 Skia 新增一个自己的 fuzzer。什么是 Skia 的 fuzzer按 fuzz/README.md 的定义fuzz/目录里保存的是 Skia 的fuzzers——即接收随机化输入、聚焦特定 API 随机执行代码的程序片段。目录中有两个典型例子codec fuzzer拿一个被变异的 png/jpeg或其他编码格式文件尝试将其解码为SkImagecanvas fuzzer把一组随机字节翻译成对SkCanvas的一系列 API 调用。这两种模式分别代表了 Skia fuzzer 的两大分类binary fuzzer强依赖随机数据的二进制格式如图片解码、SkSL 解析与API fuzzer把随机字节映射为类型化参数后驱动公开 API。后文会详细展开。fuzz/ 目录结构通用 fuzzer 与 OSS-Fuzz 入口的分层从目录组织上fuzz/分两层fuzz/*.cpp / *.h与具体输入格式无关的通用部分包括随机数据抽象 fuzz/Fuzz.h、随机对象生成器 fuzz/FuzzCommon.h、统一的命令行入口 fuzz/FuzzMain.cpp以及FuzzCanvas.cpp、FuzzPathop.cpp、FuzzDrawFunctions.cpp、FuzzGradients.cpp、FuzzEncoders.cpp等 API fuzzer 实现fuzz/oss_fuzz/*.cpp以LLVMFuzzerTestOneInput形式暴露给 libFuzzer/OSS-Fuzz 的薄封装例如 fuzz/oss_fuzz/FuzzImage.cpp、FuzzSKSL2GLSL.cpp、FuzzSKP.cpp等。这种核心逻辑 引擎适配的分层使得同一个 fuzzer 既能被fuzz可执行文件用于本地复现也能被 OSS-Fuzz 的 libFuzzer/afl-fuzz 等引擎直接驱动。Fuzz 抽象把随机字节流变成类型化参数所有 API fuzzer 的随机数据都来自 fuzz/Fuzz.h 中定义的Fuzz类fuzz/Fuzz.h。它本质上是一个只读的字节流游标fData/fSize/fNextByte记录数据缓冲区与消费位置size()、remainingSize()、remainingData()、exhausted()、deplete()提供状态查询与跳过能力signalBug()直接raise(SIGSEGV)让 fuzzing 引擎识别出该输入触发了 bugfuzz/Fuzz.h。核心消费接口是一组模板化的next系列方法fuzz/Fuzz.hnext(T*)按sizeof(T)原样拷贝字节nextRange(T*, min, max)把随机值钳制到[min, max]区间fuzz/Fuzz.h避免出现越界枚举或超大标量nextEnum(T*, max)针对枚举的区间包装规避 UBSAN 对非法枚举值的报错fuzz/Fuzz.hnextN(T*, n)连续填充 n 个元素特化的next(bool*)只取字节最低位next(SkRegion*)委托给FuzzNiceRegionfuzz/Fuzz.cpp。一个值得注意的设计细节next()刻意采用参数按指针传入而非返回值的形式注释解释是为了避免不同编译器对函数实参求值顺序不一致GCC 与 Clang 可能产生不同结果保证随机字节被消费的顺序是平台无关的fuzz/Fuzz.h。Fuzz类的注册机制由DEF_FUZZ(name, f)宏与Fuzzable结构完成fuzz/Fuzz.h宏会生成fuzz_##name函数并注册进sk_tools::RegistryFuzzable使fuzz -t api -n name能按名字查到对应 fuzzer。FuzzCommon约束随机数据的安全生成器很多 API 并不接受任意字节直接喂 NaN、无穷大或天文数字反而会淹没有效路径。因此 fuzz/FuzzCommon.cpp 提供了一系列nice生成器fuzz_nice_float过滤掉 NaN 与超过 ±1e35 的数值fuzz/FuzzCommon.cppFuzzNicePath(fuzz, path, maxOps)随机组合moveTo/lineTo/quadTo/conicTo/cubicTo/addRect/addRRect/addPath等 30 多种路径操作并限制点数不超过 100000防止自叠加路径指数膨胀导致超时fuzz/FuzzCommon.cppFuzzEvilPath与 nice 版相对允许所有 float 值用于压力更大的场景fuzz/FuzzCommon.cppFuzzNiceRRect、FuzzNiceMatrix覆盖 identity/translate/scale/affine/perspective 五类矩阵、FuzzNiceRegion矩形集合运算坐标避开SkRegion的哨兵值fuzz/FuzzCommon.cppFuzzCreateValidInputsForRuntimeEffect为 SkSL runtime effect 生成合法的 uniform 数据与子效果child参数保证随机代码能真正执行到编译与求值路径fuzz/FuzzCommon.cpp。两种可执行文件形态fuzz 与单 fuzzer 二进制fuzz/README.md 明确指出 fuzzer 有两种打包方式二者都由 BUILD.gn 定义fuzz可执行文件包含所有fuzzer是复现 fuzzer 上报 bug 的便捷工具。对应test_app(fuzz)目标BUILD.gn其源文件列表同时包含fuzz/下的通用实现与fuzz/oss_fuzz/下的全部封装。单 fuzzer 可执行文件每个只含一个 fuzzer便于直接用 libFuzzer 构建。对应skia_build_fuzzers开关下的libfuzzer_app模板BUILD.gn。libfuzzer_app模板的要点自动附加fuzz/Fuzz.cpp与fuzz/FuzzCommon.cpp作为公共源文件通过defines注入SK_BUILD_FOR_LIBFUZZER与SK_BUILD_FOR_FUZZER当启用skia_use_libfuzzer_defaults时加上-fsanitizefuzzer编译与链接标志。从 BUILD.gn 可以看到当前仓库快照中完整的单 fuzzer 目标清单约 50 个按类型可分为几组反序列化类region_deserialize、path_deserialize、textblob_deserialize、skdescriptor_deserialize、image_filter_deserialize、skp、colrv1、skcolorspace、parse_path图片编解码类image_decode、image_decode_incremental、android_codec、animated_image_decode以及png_encoder、jpeg_encoder、webp_encoderSkSL 编译类sksl2glsl、sksl2metal、sksl2pipeline、sksl2spirv、sksl2wgsl、skruntimeblender、skruntimecolorfilter、skruntimeeffect、skmeshspecificationAPI 类api_create_ddl、api_draw_functions、api_ddl_threading、api_gradients、api_image_filter、api_path_measure、api_pathop、api_triangulation、api_raster_n32_canvas、api_regionop、api_mock_gpu_canvas、api_precompile、api_null_canvas、api_skparagraph、api_svg_canvas、api_polyutils、quad_roots、cubic_roots其他格式skjson、svg_dom、skottie_json依赖SK_ENABLE_SKOTTIE/SK_ENABLE_SVG宏。fuzz 可执行文件的命令行用法与类型自动检测fuzz的入口是 fuzz/FuzzMain.cpp 的mainfuzz/FuzzMain.cpp用法为fuzz -t type -b path/to/file [-n api-to-fuzz] fuzz -b path/to/file支持的命令行参数fuzz/FuzzMain.cpp参数简写含义--bytes-b文件路径或目录路径文件内容作为 fuzz 字节目录则逐个文件依次作为输入--type-t输入解释方式见下方类型列表--name-n当--type api时指定要 fuzz 的 API 名称--dump-d非空时把image*/skp类型结果以指定文件名 dump 为 PNG--loops每个输入重复运行的次数默认 1--verbose-v打印更多 fuzzing 信息--type的合法取值在 fuzz/FuzzMain.cpp 中完整列出android_codec、animated_image_decode、api、color_deserialize、colrv1、filter_fuzz、image_decode、image_decode_incremental、image_mode、image_scale、json、path_deserialize、region_deserialize、region_set_path、skdescriptor_deserialize、skmeshspecialization、skottie_json、skp、skruntimeblender、skruntimecolorfilter、skruntimeeffect、sksl2glsl、sksl2metal、sksl2pipeline、sksl2spirv、sksl2wgsl、svg_dom、textblob。若省略--typefuzz会基于文件名猜测类型fuzz/FuzzMain.cpp对形如clusterfuzz-testcase-minimized-xxx-123或api-xxx-abcdef的命名通过正则匹配出类型/API 名再查表cf_map/cf_api_map映射到 Skia 内部名称——这两个映射表正是为直接从 ClusterFuzz 下载的复现用例设计的fuzz/FuzzMain.cpp。image_mode/image_scale还展示了一个省 fuzzer 的技巧calculate_option()对输入前 1024 字节求和并截取为 8 位整数fuzz/FuzzMain.cpp使 afl-fuzz 无需额外参数就能确定性地产出不同的缩放倍率1x/2x/4x/8x/16x或解码模式全图/scanline/分条/subset/动画从而把多个 fuzzer 合并成一个。API fuzzer 实例FuzzCanvas 的随机绘制fuzz/FuzzCanvas.cpp 是 README 中提到的 canvas fuzzer 的实现。它用Fuzz递归地随机构造出完整的绘制树例如make_fuzz_colorfilterfuzz/FuzzCanvas.cpp通过nextRange在 0~8 之间选择 colorfilter 类型随机生成颜色、混合模式、颜色矩阵、组合滤镜等再交给SkCanvas执行绘制make_fuzz_image、make_fuzz_picture等则构造位图与SkPicture。整棵随机对象树的构造在 fuzz/FuzzCanvas.cpp 的make_fuzz_tT辅助模板上展开——注释特别警告不要在同一表达式中多次调用next()类函数否则求值顺序不确定。Binary fuzzer 实例image_decode 与 LLVMFuzzerTestOneInputbinary fuzzer 的典型代表是 fuzz/oss_fuzz/FuzzImage.cpp它把输入字节直接当作编码图片数据经SkImages::DeferredFromEncodedData延迟解码后绘制到 128×128 的栅格表面。其入口extern C int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size 10240) { return 0; } // 限制输入规模防止超大图片拖垮引擎 FuzzImageDecode(data, size); return 0; }fuzz/oss_fuzz/FuzzImage.cpp这段代码体现了 OSS-Fuzz 生态的标准契约LLVMFuzzerTestOneInput由 libFuzzer 反复调用输入被 10 KB 上限截断以保证吞吐。所有fuzz/oss_fuzz/下的封装FuzzSKP、FuzzSKSL2GLSL、FuzzRegionDeserialize等都遵循同一模式且各自带有#if defined(SK_BUILD_FOR_LIBFUZZER)保护因此同一份源文件也能编译进fuzz可执行文件。持续模糊测试接入 OSS-Fuzz 的完整流程fuzz/README.md 说明 Skia 通过 Google 的 OSS-Fuzz 进行持续 fuzzing后者驱动 libFuzzer、afl-fuzz、honggfuzz 等引擎并能在发现问题时自动在 OSS-Fuzz issue 跟踪器中创建/关闭 bug。OSS-Fuzz 仓库中维护着一个专门的 Skia 项目目录用于增删改自动运行的 fuzzer如需在本地用 Docker 验证 OSS-Fuzz 构建可参照 OSS-Fuzz 官方新项目指南中的本地测试一节。当需要在 OSS-Fuzz 中启用一个新的 fuzzer时README 给出了三步操作添加种子语料seed corpus到gs://skia-fuzzer/oss-fuzz/位于 skia-public 项目通过 Web UI 给 zip 文件授予allUsers的 Reader 角色确保语料文件公开可读更新 OSS-Fuzz 仓库中 Skia 项目的 Dockerfile把种子语料下载进构建镜像更新build.sh构建目标 fuzzer 并把产物移入$OUT若有种子语料同样移入$OUT且命名必须与 fuzzer 可执行文件同名、以_seed_corpus.zip为后缀——引擎会据此自动关联语料做变异。README 特别标注第 1、2 步主要针对binary fuzzer如image_decode、sksl2glsl这类强依赖输入格式的 fuzzerAPI fuzzer 通常不需要种子语料。README 还给出了两个真实的历史 PR 作为参照一个 binary fuzzer 的添加示例与一个 API fuzzer 的添加示例。除 Skia 主仓库外OSS-Fuzz 还为独立的skcms仓库配置了专门的 OSS-Fuzz 目录其构建流程类似区别在于build.sh直接编译 fuzz 可执行文件而不经过 GN 目标。OSS-Fuzz 仪表盘与覆盖率报告运行状况的观测方面README 指向 OSS-Fuzz 的 fuzzer 统计面板其指标包括executions per second每秒执行次数越高越好edge coverage percent每个 fuzzer 的边覆盖率百分比OOM / timeout / crash 占比多少比例的 fuzzing 运行以这三种方式结束corpus_backup全部已 fuzz 输入的语料备份。面板需要向 OSS-Fuzz 维护者申请查看权限。README 中还提到 OSS-Fuzz 提供的全部 Skia fuzzer 合并覆盖率报告coverage report以及按 fuzzer/按日期维度查看的示例仪表盘链接。这些面板可直接用于判断某个 fuzzer 是否健康、覆盖率是否停滞。如何为 Skia 新增一个 fuzzer结合上文源码新增 fuzzer 的推荐路径是在fuzz/下实现核心逻辑签名形如void FuzzXxx(Fuzz* fuzz)或bool FuzzXxx(const uint8_t* data, size_t size)参考 fuzz/FuzzCommon.h 中FuzzNiceRegion等既有声明若走 API fuzzer 路线用DEF_FUZZ(name, f)宏注册进 registryfuzz/Fuzz.h即可被fuzz -t api -n name调用在 BUILD.gn 的skia_build_fuzzers分支下新增一个libfuzzer_app(your_fuzzer)目标API fuzzer 需同时列入 BUILD.gn 的test_app(fuzz)源列表源码放在fuzz/oss_fuzz/下并暴露LLVMFuzzerTestOneInput本地先用fuzz -b 用例复现再用-fsanitizefuzzer构建的单 fuzzer 二进制做长时间运行按上文三步走接入 OSS-Fuzz并利用 fuzzer-stats 面板持续观察覆盖率与崩溃率。小结Skia 的 fuzzing 体系由三块拼图构成Fuzz字节流抽象与FuzzCommon安全生成器保证随机数据能被 API 高效、合法地消费、fuzz/libfuzzer_app两种构建形态分别服务本地复现与引擎驱动、以及 OSS-Fuzz 流水线种子语料、_seed_corpus.zip命名约定与统计面板。理解这三层即可熟练复现 Skia 的 fuzzer 崩溃报告也能在仓库中定位任意fuzz/oss_fuzz/文件对应的实现与构建目标。README 末尾还以 See Also 形式收录了两份关于创建 binary fuzzer / 创建 API fuzzer的设计文档可供进一步参考。赞分享图形学图像处理【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images.项目地址https://gitcode.com/gh_mirrors/skia1/skia点击查看免费下载相关推荐Skia 模糊测试Fuzzing完全指南从 fuzz 复现到 OSS-Fuzz 持续集成Skia 模糊测试Fuzzing完全指南从 fuzz 复现到 OSS Fuzz 持续集成 导读 本文以 fuzz/README.md https://li图形学OSS-Fuzz 全解析为开源软件构建持续模糊测试Fuzzing体系OSS Fuzz 全解析为开源软件构建持续模糊测试Fuzzing体系 导读 本文以 OSS Fuzz 项目主文档为核心系统讲解 Google 面向开源软测试应用安全质量保障Skia Fuzzing 实战指南用 fuzz 复现崩溃、用 libFuzzer 编写模糊测试器并接入 OSS-FuzzSkia Fuzzing 实战指南用 fuzz 复现崩溃、用 libFuzzer 编写模糊测试器并接入 OSS Fuzz 本文基于 Skia 官方测试文档 s图形学上一篇PotPlayer字幕翻译终极指南免费实现双语观影体验下一篇PotPlayer字幕翻译终极指南免费实现外语视频实时翻译的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表