
GDCM 中的六个解析器/编解码器缺陷,在 v3.2.6 上以 sanitizer 失败或有界传播检查的形式复现。每个自动触发都有一个接近有效的对照,不会产生易受攻击的信号。发现 1 还包含一个插桩的控制流原语。
供维护者和漏洞协调者审查。运行任何内容之前请阅读 SAFETY.md。
manifest/targets.env:
| 名称 | 修订 | 说明 |
|---|---|---|
vulnerable | 9c71b163 | 标签 v3.2.6 |
master | 2cd05d13 | 静态审查的上游 master 快照;运行时矩阵待定 |
fixed | 未设置 | 仅在存在经过审查的修复提交后填充 |
master 是带日期的快照,不是移动分支。两个修订都可以从公共仓库访问,因此 bootstrap.sh 可以在没有任何私有源代码的情况下准备任一版本。
本仓库中的运行时证据针对 v3.2.6。下面的更广范围来自源代码历史检查;涉及的代码模式也保留在固定的 master 快照中。
fixtures/ - 惰性 DICOM 输入,SHA-256 固定在 manifest/expectations.json 中,并在每次触发运行前验证generators/ - 每个 fixture 的确定性、无依赖源代码生成器harnesses/ - 最小读取/编码/解码测试框架;发现 2 通过 gdcmconv CLI 和服务器会调用的库转码 API 展示manifest/expectations.json - 机器可读的命令、决定性信号以及 fixed 目标的验收标准scripts/ - 固定源代码准备、sanitizer 构建、有界执行、清理evidence/ - 已观察到的简明结果,未测试的目标明确说明LICENSE - MIT 许可证一个可丢弃的 Linux 或 macOS 构建环境,包含 Git、Python 3、CMake 3.20+、Ninja 以及 C++11 工具链(Clang 或 GCC)。在 Ubuntu 上:git python3 cmake ninja-build clang zlib1g-dev。设置 CC/CXX 以改用 GCC。
源代码准备通过 HTTPS 克隆,除非 GDCM_SOURCE_REPO 指向现有的本地克隆。不使用 SSH 主机。
这些命令仅准备源代码和构建产物;它们不会打开任何 fixture。
./scripts/build-target.sh vulnerable asan debug
./scripts/build-target.sh vulnerable ubsan debug
./scripts/build-target.sh master asan debug
./scripts/build-target.sh master ubsan debug
第三个参数是配置文件。debug 是 -O0 -g;release 是 -O2 -g -DNDEBUG,它会消除 GDCM 的 gdcm_debug_assert(),并匹配发行版构建库的方式。在两种配置下运行矩阵可以回答维护者提出的第一个问题,即报告是否是启用断言构建的产物。
GDCM_SUPPORT_BROKEN_IMPLEMENTATION=ON 是 GDCM 自己的默认值,保持不变。使用 JOBS=8 覆盖保守的并行度。
每次构建都会将 build-info.json(修订、编译器、标志、平台)写入其 GDCM 构建树,并且每次运行摘要都会嵌入它,因此归档的证据是自描述的。
export GDCM_REPRO_ACK=I_UNDERSTAND_THIS_CRASHES_A_LOCAL_PROCESS
./scripts/run-matrix.sh vulnerable master --profile debug # 所有自动化用例
./scripts/run-one.sh vulnerable f1 # 一个触发器
./scripts/run-one.sh vulnerable f1 --control # 其对照
run-matrix.sh 为每个目标运行每个自动化用例,不会在第一次失败时停止,并写入 _runs/matrix-<stamp>.json 以及渲染后的 _runs/matrix-<stamp>.md。两阶段的 f1-exploit 用例保持手动,并如实报告,而不是被错误分类为失败的自动化用例。
每个子进程都禁用核心转储并设置 15 秒超时;发现 5 还额外获得有界栈限制。输出保留在 _runs/ 下。分类器匹配 sanitizer 类别和涉及的函数,从不匹配地址、PID 或源代码行号。
对于 vulnerable,当决定性信号出现且其对照保持干净时,用例通过。对于 master,运行器记录观察结果而非预先声明的判定。对于 fixed,仅当信号不存在、没有其他 sanitizer 或致命信号出现,并且测试框架返回允许的干净结果时,用例才通过。这些规则在 FIXED_REV 指定实际补丁之前是临时的;必须根据该补丁预期的拒绝或处理行为进行审查。
另外两个测试框架是可利用性研究而非复现用例,仅在 Linux x86-64 上的非 sanitizer 配置中构建:
| 测试框架 | 发现 | 确立内容 |
|---|---|---|
finding01_groom | 1 | 通过分配记录钩子观察到的已测试 glibc 邻接关系 |
finding03_leak | 3 | 131070 字节的过度读取可以暴露构建特定的库指针 |
evidence/v3.2.6-macos-arm64-debug.md 记录了完成的 v3.2.6 调试矩阵,包括每个对照和两个有界的发现 3 传播检查。
evidence/v3.2.6-linux-x86_64-finding01-groom.md 和 evidence/v3.2.6-linux-x86_64-finding03-leak.md 记录了下面的两个可利用性结果。当前 master、完整的 release 配置矩阵以及 f1-exploit 结果在其记录被保留之前不予声明。
./scripts/clean.sh
清理在没有包标记的情况下拒绝运行,并且仅删除本仓库下的 _work、_build、_generated、_runs 和 Python 字节码缓存。evidence/ 下保留的证据不会被删除。
f1-exploit 仅限 Linux-x86_64,并且手动运行;manifest/expectations.json 包含确切的命令序列。在测试框架的确定性分配布局下,它测试三个独立的事实,每个都有匹配的负例:
f1 fixture,会报告损坏但明确不是内容控制,因此该检查是可证伪的;在 12288 字节溢出中的 8 字节窗口中,大约一半接受任意值。其余是耦合的,因为 DoYBRFull422 将一个源字节复制到两个输出位置;偏移 6144 是自由窗口之一。帧 1 的解码最后运行,因此持续超过分配的是帧 1 的内容。
测试框架记录 ImageReader::Read() 是否在相邻对象被修改时返回 true。在将结果描述为观察到的证据之前,必须保留成功的 Linux x86-64 记录。
f1-exploit 提供自己的受害者布局,因此它无法回答未修改的进程是否具有该布局。finding01_groom 使用原版 glibc、默认 PIE 和 ASLR,并使用全局分配钩子记录但不重定位分配。在保留的测试中:
finding01 测试框架在完全没有插桩的情况下以相同方式死亡。在已测试的 glibc 构建上,发现 1 可靠地导致拒绝服务;未发现代码执行路径。 测试的几何布局是固定的,其他分配器或平台可能以不同方式布置堆。
finding03_leak 是更强的结果。在已测试的构建中,越界读取到达 131070 字节,一个 gdcm::ByteValue vtable 指针进入解码像素,测试框架使用该构建已知的 vtable 偏移推导出库加载基址。这是一个本地 API 级别的泄露结果:它需要 LUT 应用和对解码像素缓冲区的访问。它并未表明网络服务会返回这些像素。
两者在这里无法链接成代码执行,不仅因为没有找到受害者:它们需要不同的 PhotometricInterpretation 值,因此需要两个文件,而且泄露的基址仅在泄露进程仍然存活时有用。
sanitizer 报告证明了在已测试进程和修订中所述的记忆安全或未定义行为事件。f1-exploit 在故意提供目标布局的插桩分配器下测试字节控制和相邻函数指针覆写。它并未在未修改的消费者中确立该布局。保留的 finding01_groom 试验在已测试的几何布局和 glibc 构建中未观察到该布局。
这些都不能证明任何特定产品中的远程可达性、持久性或下游适用性。给定部署的可达性论证是一个单独的声明,在披露文本中提出,而非由本包提出。
| # | CWE | 源代码检查范围 | 所需路径 |
|---|
| 1 | CWE-787 | v3.0.4 至 v3.2.7 | 多帧 RLE YBR_FULL_422 读取 |
| 2 | CWE-787 | v2.0.16 至 v3.2.7 | JPEG2000 编码/转码 |
| 3 | CWE-125 | v2.0.5 至 v3.2.7 | 分段调色板解析;LUT 应用暴露传播的值 |
| 4 | CWE-787 | v2.0.8 至 v3.2.7 | ImageRegionReader::ReadIntoBuffer;与 CVE-2024-22373 之后不完整的精度验证相关 |
| 5 | CWE-674 | v2.0.4 或更早至 v3.2.7 | 普通嵌套序列解析 |
| 6 | CWE-369 | v2.0.4 或更早至 v3.2.7 | 使用 NumSegments=0 的普通 RLE 解析 |
| 用例 | 发现 | 展示内容 |
|---|
f1 | 1 | RLECodec::DecodeFragment 中的 ASan 堆写入 |
f1-exploit | 1 | 插桩的相邻对象覆写和间接分支控制(Linux x86-64) |
f2 | 2 | 通过 gdcmconv --j2k 在 opj_write_from_memory 中的 ASan 堆写入 |
f2-lib | 2 | 通过 ImageChangeTransferSyntax::Change 的相同写入 |
f3 | 3 | 分段调色板扩展中的 ASan 堆读取 |
f3-propagation | 3 | 越界字节到达解码像素,以计数形式报告 |
f3-sentinel | 3 | 一个有界的已知保护字跨越逻辑 LUT 边界 |
f4 | 4 | JPEG2000 区域解码中的 ASan 堆写入 |
f5 | 5 | 嵌套序列项上的 ASan 栈耗尽 |
f6 | 6 | RLE 解码中的 UBSan 除零;x86 上的 SIGFPE |