Jellyfin 如何搭建 AFL++ 与 SharpFuzz 环境并运行模糊测试用例?
【免费下载链接】jellyfinThe Free Software Media System - Server Backend & API项目地址: https://gitcode.com/GitHub_Trending/je/jellyfin
Jellyfin 仓库的fuzz/目录下内置了两个基于 SharpFuzz 的模糊测试工程,用来对Jellyfin.Api与Emby.Server.Implementations中的特定函数做 AFL++ 驱动的模糊测试。本文按 fuzz/README.md 的流程,说明如何安装 AFL++ 与 SharpFuzz 工具、选择仓库已有的模糊测试用例并实际运行,以及如何判断运行是否按预期进行。
仓库中已有哪些模糊测试用例
两个 fuzz 工程各提供一组入口,用例名在 Program.cs 与 Program.cs 的switch分支中定义,fuzz.sh的第一个参数就是这些用例名:
| 工程目录 | 可用用例名 | 被测对象 |
|---|---|---|
| fuzz/Jellyfin.Api.Fuzz | UrlDecodeQueryFeature | UrlDecodeQueryFeature 中间件 |
| fuzz/Emby.Server.Implementations.Fuzz | PathExtensions.TryReplaceSubPath | PathExtensions.TryReplaceSubPath |
| fuzz/Emby.Server.Implementations.Fuzz | SqliteItemRepository.ItemImageInfoFromValueString | SqliteItemRepository.ItemImageInfoFromValueString |
每个用例在对应工程的Testcases/<用例名>/下带有种子输入文件(如 test1.txt),例如UrlDecodeQueryFeature的种子是一段 URL 编码字符串a%3D1%26b%3D2%26c%3D3。
环境前提
- 两个 fuzz 工程均面向
net10.0(见 Jellyfin.Api.Fuzz.csproj),且 global.json 固定要求 .NET SDK10.0.0(rollForward: latestMinor),因此运行环境需要 .NET 10 SDK。 - 仓库通过 Directory.Packages.props 统一管理
SharpFuzz包版本(2.3.0),构建 fuzz 工程时会自动还原。 - AFL++ 需要从源码编译安装,使用
make与 root 权限(sudo)。
第一步:安装 AFL++
按 fuzz/README.md 的 Setup 说明执行:
git clone https://github.com/AFLplusplus/AFLplusplus cd AFLplusplus make all sudo make install注意sudo make install会以管理员权限把 AFL++ 安装到系统目录(含afl-fuzz等命令),这是一次影响系统环境的操作;如果当前账号没有 sudo 权限,需要先向环境管理员申请或改用具备权限的机器。
第二步:安装 SharpFuzz.CommandLine 全局工具
dotnet tool install --global SharpFuzz.CommandLine这个全局工具提供sharpfuzz命令,fuzz 脚本用它对目标程序集做插桩。
第三步:进入目标 fuzz 工程目录并运行脚本
fuzz/README.md 说明:在对应工程的目录中运行fuzz.sh,并传入要执行的模糊测试用例名。以Jellyfin.Api.Fuzz的UrlDecodeQueryFeature为例,从仓库根目录切入后执行:
cd fuzz/Jellyfin.Api.Fuzz sh fuzz.sh UrlDecodeQueryFeature其他用例同理,在 fuzz/Emby.Server.Implementations.Fuzz 目录下运行:
sh fuzz.sh PathExtensions.TryReplaceSubPath # 或 sh fuzz.sh SqliteItemRepository.ItemImageInfoFromValueString用例名必须与Program.cs中switch分支的字符串完全一致,传入未知名称时进程会抛出ArgumentException: Unknown fuzzing function: <你传入的名称>。
脚本内部做了哪些事
以 fuzz/Jellyfin.Api.Fuzz/fuzz.sh 为例,脚本内容很短,执行顺序为:
dotnet build -c Release ../../Jellyfin.Api/Jellyfin.Api.csproj --output bin sharpfuzz bin/Jellyfin.Api.dll cp bin/Jellyfin.Api.dll . dotnet build mkdir -p Findings AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net10.0/Jellyfin.Api.Fuzz "$1"- 第一行:Release 构建被测工程(
Jellyfin.Api),输出到脚本同级的bin目录。 - 第二行:用
sharpfuzz对bin/Jellyfin.Api.dll插桩,生成可供 AFL++ 在进程外调用的版本。 - 第三行:把插桩后的
Jellyfin.Api.dll复制回工程目录。这一步是必要的,因为 Jellyfin.Api.Fuzz.csproj 通过<HintPath>Jellyfin.Api.dll</HintPath>本地引用工程目录下的Jellyfin.Api.dll,复制后 fuzz 工程才会链接到插桩版本。 - 第四行:构建 fuzz 工程本身(Debug)。
- 最后一行:启动
afl-fuzz,种子输入目录为Testcases/<用例名>,结果输出到Findings/<用例名>,-t 5000是脚本为单次执行设置的超时参数,AFL_SKIP_BIN_CHECK=1是脚本设置的 AFL++ 环境变量,用于跳过其对二进制的检查。
Emby.Server.Implementations.Fuzz的 fuzz.sh 结构完全相同,只是构建对象换成了Emby.Server.Implementations工程、harness 路径换成了./bin/Debug/net10.0/Emby.Server.Implementations.Fuzz。
脚本开头有set -e,任何一步失败(例如sharpfuzz未安装、目标工程构建失败)都会立即中止,所以“脚本一路跑完并进入afl-fuzz前台运行”本身就说明前几步成功。
如何判断运行结果
afl-fuzz在前台持续运行,把发现的用例写入Findings/<用例名>/目录;脚本不会自动生成该目录之外的其他产物。- 传错用例名时,进程会直接抛出上面提到的
ArgumentException,这是脚本流程中最快的失败信号。 - 种子输入需要符合各用例期望的格式:
PathExtensions.TryReplaceSubPath的输入按:切分且必须恰好得到 3 段(见 Program.cs 中data.Split(':')的判断),不满足时该输入会被跳过;仓库自带的种子 test1.txt 中夹带了原作者的本地路径(/home/bond/dev/jellyfin/),只作为种子示例存在。
边界与限制
- 仓库当前只提供上表列出的三个用例;harness 中没有的函数无法直接模糊测试,需要自行在对应工程的
Program.cs中新增分支。 - 运行依赖 .NET 10 SDK(global.json),在低版本 SDK 上构建会直接失败。
- 本文只覆盖
fuzz/README.md给出的安装与运行流程,未涉及如何向 AFL++ 添加自定义编译器选项或使用托管版 AFL 编译器,仓库文档中没有对应说明。
【免费下载链接】jellyfinThe Free Software Media System - Server Backend & API项目地址: https://gitcode.com/GitHub_Trending/je/jellyfin
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考