oss

一份 LUT 在改变任何像素之前,就越过了 OpenColorIO 的信任边界

11 条来源 8 条一手来源 已翻译 2026年9月7号

正文
一名调色师坐在昏暗调色室的控制台前,面对显示电影画面与色彩控制项的监视器。

2015 年,调色师在墨西哥国家电影资料馆使用 Assimilate Scratch 调色。画面展示一间真实的调色室,未展示 OpenColorIO 界面;它呈现的是制作管线面向人的一端:微小的变换文件可以进入体量庞大、权限较高的应用程序。Erwin Verbruggen 摄。[11]

查找表看上去不像会运行的程序。在调色室里,它更接近一种创作素材:这个小文件把输入值映射为输出值,让摄像机画面、审片监视器、视觉特效镜头或交付母版按预期呈现。OpenColorIO 于 2026 年 5 月发布的安全公告揭示了这种直觉背后的风险。它的四个 LUT 读取器都存在一类代码路径,会把文本 token 写入固定大小的栈缓冲区,却没有限制 token 长度。非 Windows 版本同时暴露于全部四种格式,Windows 版本也有两个读取器存在危险路径。精心构造的色彩素材因此可以在打开它的应用程序中破坏内存,而此时变换尚未改变任何像素。[1][3][4]

OpenColorIO 2.5.2 修复了 .spi3d.spi1d.cube.lut 文件的相关路径。项目发布说明指出,所有更早的 OCIO 1.x 和 2.x 版本均受该 CVE 影响,2.5.2 则与 2.5.1 保持 ABI 兼容。[1] 后一项信息降低了其中一种升级路线的难度,应急处置范围仍然远大于单一软件包。OCIO 作为库嵌入创作应用、插件、命令行工具、Python 环境、容器和渲染镜像。真正需要修补的单位,是每一条能够解析色彩素材的执行通道;管理员最先找到的 libOpenColorIO 软件包只是其中之一。

本文复盘的是一条易受攻击的代码路径,不主张已有工作室遭到入侵。这里引用的公开来源记录了一次概念验证性质的解析器故障,没有记录制作环境遭入侵的事件。CISA 的补充信息把利用情况标为“poc”,自动化程度标为“no”;CNA 评定的 CVSS v4 场景采用 Local 攻击向量和 Active 用户交互。[4][9] 这些界限应约束处置尺度,却不足以成为继续暴露解析器的理由。

封面照片拍摄于 2015 年,画面中的调色师正在墨西哥国家电影资料馆使用 Assimilate Scratch。[11] 它提供背景语境,不充当漏洞证据,图片来源也没有说明这台工作站使用了 OpenColorIO。照片的价值在于呈现尺度反差:一项色彩决定以小型素材的形态抵达,随后进入能够访问帧素材、项目存储、缓存、凭据,有时还能连接渲染农场的应用程序。解析器会继承该应用程序的权限。

故障所在:一种 C 语言陋习在四个读取器中重复出现

最清楚的案例来自 Spi3D 读取器。它先把一行文本读入一个 4,096 字节数组,再调用 C 语言的 sscanf,用未设宽度上限的 %s 转换把三个值分别写入三个 64 字节字符数组。%s 遇到空白字符才停止;缺少宽度限制时,它无法得知目标缓冲区的容量。项目安全公告显示,一个很长的 token 就能让缓冲区溢出约 4,000 字节。公告将该问题评为 8.4 分、High,并说明凡是通过 OCIO API 或工具加载恶意 .spi3d 文件,攻击者控制的数据都能抵达栈内存。[4]

相同的解析假设还出现在相邻的三种格式中。Spi1DFrom 文件头和数据行使用了无界读取。Iridas .cube 读取器把 DOMAIN_MINDOMAIN_MAX 的值解析进 64 字节数组。旧版 Discreet .lut 读取器则把一个 token 写入 16 字节数组。各平台的情况并不对称:在 Windows 和非 Windows 系统上,Spi3D 与 Discreet .lut 都会进入普通 sscanf 的危险路径;Spi1D.cube 的 Windows 分支此前已经使用带目标容量参数的 sscanf_s。拉取请求 2307 在这些读取器中加入 %63s%15s 等明确宽度,为结尾的空字节留出空间,同时把 Windows 版 Spi3D 调用改为正确的 sscanf_s。[1][3][4]

四个格式语法沿用了同一种危险习惯,补丁因此改动了四个源文件,不过实际受影响的格式集合随平台而变。在非 Windows 系统上,四个读取器全都需要修复。Windows 上已披露的溢出路径位于 Spi3D 和 Discreet .lut;补丁也进一步加固了另外两个读取器中原本已传入容量的分支。[3][4]

这一区别会影响处置范围。只封禁 .spi3d,可以覆盖 CVE 数据库简短描述中点名的格式,却会漏掉其他已经修复的读取器。只扫描某个概念验证字符串也有同样的问题。处置范围应以发布版和补丁为准:凡是运行易受攻击版本的地方,都要覆盖所有受影响的读取器。[1][3][9]

“High”评级也没有把每次超长 token 都判定为必然发生代码执行。栈覆盖会让进程终止;要把它转化为攻击者掌控的代码执行,还取决于具体构建、平台、编译器防护、宿主内存布局和输入路径。公告描述的是一种严重且合理的结果,没有声称每种应用集成都具备同等可利用性。[4] SUSE 提供了一个有参考价值的下游对照:它把该问题评为 Moderate,同时仍为 Tumbleweed 发布了修复后的 OpenColorIO 2.5.2 软件包。[10] SUSE 没有在该页面解释评级差异。这一对照应促使部署团队分析各自环境中的可达性,同时保持上游划定的版本界限。

信任边界藏在 FileTransform 里面

OpenColorIO 自己的安全文档给出了架构层面的线索。一个 config.ocio 文件可以引用外部变换文件。这些文件的体积可以任意增长,可以位于任何能够访问的卷上,并会在 Processor 需要它们时延迟加载。搜索路径可以包含环境变量替换。项目还明确警告,修改过的环境能够把读取操作重定向到不安全的位置。[2]

另一个容易忽略的特性来自 FileTransform:文件扩展名不构成格式证明。API 文档指出,即使文件使用不受支持的扩展名或根本没有扩展名,它也会依次尝试已注册的读取器,直到其中一个成功。[5] 这种行为适合处理并不整齐的制作管线,同时也说明扩展名白名单只能用于分类,无法充当安全边界。给传入文件改名,不会移除随后检查其内容的解析器。

一条具有代表性的路径如下:

  1. 艺术家、自动化进程或渲染作业选择一份项目配置或 look 包。
  2. 配置通过搜索路径和运行时上下文解析一个 FileTransform
  3. 应用程序要求 OCIO 构造所需的处理器。
  4. OCIO 延迟打开被引用的文件,再根据内容选择读取器。
  5. 在易受攻击的构建中,四个读取器之一可以覆盖宿主进程的栈内存。

在这条链路中,LUT 只要交给程序解释,攻击条件便已具备;文件本身仍然是普通数据。“Local”和“Active”描述的是已发布 CVSS 向量所评分的场景:易受攻击的进程需要在某种操作下加载该素材;评分模型没有采用“未经认证的协议请求直接进入解析器”这一远程路径。[4] 这些标签无法涵盖每一种集成方式。面向网络的摄取服务或远程提交的渲染任务,可以把这个“本地”解析步骤暴露在更广的工作流中。该向量也不会告诉工作室,文件究竟来自内部色彩部门、供应商交接、自由职业者提交的软件包、市场下载、旧项目归档,还是可写的共享目录。实际暴露程度取决于这些部署问题。

Blender 的独立文档从应用程序一侧展示了分发难题:Blender 使用 OCIO 管理色彩,也可以与其他应用共享一份 OCIO 配置。[8] 互操作性正是这一功能的用途。与此同时,同一个配置与 LUT 捆绑包会在异构宿主间流转,而各宿主捆绑的库版本、文件访问权限和沙箱条件各不相同。更新 Python wheel 覆盖不到应用程序的私有副本;更新工作站也不会重建昨天生成的渲染容器。

第一阶段:以实际运行环境为清点对象

先建立一张矩阵,以工作真正执行的地方作为每一行:艺术家工作站、审片工作站、渲染节点镜像、转码 worker、摄取服务、农场提交工具、插件宿主、Python 环境,以及验证项目包的 CI 作业。每一行都要记录宿主应用及版本、操作系统、OCIO 的供应方式、运行时 OCIO 版本、配置来源、是否接受外部 LUT、进程身份、可达存储和负责人。

开发软件包的版本不能代表运行时版本。OpenColorIO 向 Python 集成提供 PyOpenColorIO.GetVersion(),其工具也会报告实际加载的库;供应商应用有时会在诊断信息或依赖清单中显示该值。[6][7] 宿主无法给出可信报告时,应检查随应用交付的二进制文件或询问供应商。把不确定项如实记下,避免从“我们安装了 2.5.2”直接推导出“每个应用都已修复”。

修复目标是上游 2.5.2,或能够证明已经回移相同补丁的供应商构建。上游声明 2.5.2 与 2.5.1 ABI 兼容,但这项声明不授权团队把新的共享库直接放入针对旧主版本或次版本构建的任意应用。[1] 商业 DCC 软件包和紧密耦合的插件需要采用供应商支持的更新。容器与渲染镜像需要重新构建和部署;只在源代码控制中改动基础镜像标签,运行中的实例不会随之更新。

以下三个问题可用于排列各条通道的优先级:

一台使用集中管理只读配置、又不接收第三方 LUT 的单用户工作站,攻击路径要窄于把传入项目包展开到共享存储的多供应商工作室。两者都应更新。后一种环境还需要隔离措施,因为一次用户操作就可以扩散至整个渲染农场。

第二阶段:把色彩素材纳入依赖项台账

补丁封堵了本次披露的溢出,却无法保证今后的每个解析器都不出错;OpenColorIO 的安全政策也没有作出这种承诺。[2] 长期处置需要把已经用于脚本和插件的控制措施同样用于配置与变换文件。

经批准的项目配置和 LUT 集应存放在带版本记录的只读捆绑包中。清单要记录路径、大小、加密哈希、来源、审核人和批准日期。发布时解析上下文变量与搜索路径,以便操作人员查明某个项目版本究竟会加载哪些字节。新的供应商 LUT 在进入制作共享目录前,需要先经过隔离区和审核;邮件附件与下载目录应留在隐式搜索路径之外。

验证工作必须放在已打补丁的低权限 worker 上运行。ociocheck 可以识别 YAML 和 OCIO 特有的一致性错误,但文档对其能力范围有明确限定:它可以验证配置能够加载、引用关系连贯,却无法验证变换在艺术效果或数值上是否正确。[6] 从安全角度看,成功解析同样不能证明文件无害。验证应作为一个受限步骤,随后还要执行有代表性的变换测试,并把图像与经批准的结果比较。

安全门禁的规则范围应超出这次利用样本。即便限制文件总大小,长度足以冲破 64 字节缓冲区的恶意 token 仍可通过。扩展名过滤会漏掉按内容选择读取器的行为。[5] 杀毒签名可以识别已发布的概念验证样本,输入一经重新排列就会超出该签名的覆盖范围。更可信的控制项包括已修复的解析器、来源追踪、最小权限,以及一处专门用于首次解释不受信任文件的狭窄入口。

第三阶段:让系统承受解析器崩溃而不扩大损失

创作软件通常拥有较宽的访问权限,因为应用能够浏览主目录、项目共享、缓存和审片输出时,交互式工作更方便。渲染 worker 的读取权限有时还要更广。这种便利会让原生解析器中的可利用缺陷蔓延成身份与存储问题。

自动摄取和渲染应使用服务账户运行,这些账户不能读取艺术家的凭据,也不能写入源素材。在工作流允许的地方,把已批准输入挂载为只读。为 worker 分配独立暂存空间,限制网络出站连接,并把发布操作放到后续经认证的步骤中,与解析动作解耦。小型工作室即使无法隔离每一个桌面应用,仍可限制桌面应用所持 token 的权限,避免其等同于渲染农场管理员,同时确保主配置共享目录不可写。

调查所需证据应得到保存:宿主和 OCIO 版本、解析后的配置路径、LUT 哈希、提交人、作业 ID、解析器 stderr、符合留存政策的崩溃转储,以及运行作业的 worker 镜像。畸形素材引发的解析器崩溃应进入安全分诊流程,来源在外部时尤其如此。没有发生崩溃,也无法证明敌意素材在解析时未造成内存破坏或其他影响。

如果可疑 LUT 已在受影响宿主上加载,安装 2.5.2 只能保护下一次运行,无法恢复此前那次运行的安全状态。此时应隔离系统,保存素材和进程证据,查明宿主能够使用的权限与凭据,再依据暴露情况轮换凭据或重建系统。该 CVE 本身不足以断定已经发生入侵;随后一次正常渲染,也无法排除此前已经出现内存破坏事件。

值得带走的经验,远大于四个宽度说明符

代码修复小而清楚,值得肯定。限制转换宽度,把无界写入改成了有界解析;改动经过审查,项目随后发布安全版本。[1][3] 运行层面的修复范围更大,因为 OpenColorIO 位于互操作接缝处。不同应用依靠它共享配置、角色、变换与文件,从而对色彩达成一致。这道接缝越普及,一项受信任素材就会传播得越远。

工作室应继续保留这种互操作性,同时重新界定 LUT 的身份。它依然是一项创作素材;原生库开始解析它之后,它也进入软件输入、依赖项和潜在安全边界的范畴。把它纳入版本管理,记录它的流向,并先在能够安全失败的环境里打开。解析器修复发布时,所有会接触该文件的进程都要更新;搜索起来最方便的那个软件包,只是其中一处。

来源

  1. Academy Software Foundation,OpenColorIO v2.5.2 发布说明——受影响的版本范围、四个已修复的 LUT 读取器、发布日期,以及与 2.5.1 的 ABI 兼容性。
  2. OpenColorIO 技术指导委员会,“Security and OpenColorIO”——关于配置与 LUT 的信任指引、变换的延迟加载、环境变量展开路径和文件格式预期。
  3. Doug Walker,“Improve LUT loading checks (CVE-2026-42450)”,OpenColorIO 拉取请求 2307——对四个受影响读取器实现的补丁及审查记录。
  4. OpenColorIO 安全公告 GHSA-rxp3-rrgx-f547——Spi3D 缓冲区大小、输入路径、概念验证、受影响版本、可达性和 CVSS v4 向量。
  5. OpenColorIO API 文档,FileTransform——支持格式的发现方式,以及文件扩展名不受支持或缺失时根据内容选择读取器的行为。
  6. OpenColorIO 文档,“Using OCIO”——ociocheck 的验证范围、支持的 LUT 格式和随附的命令行工具。
  7. OpenColorIO API 文档,“Global”——PyOpenColorIO.GetVersion() 及其编译期等效项。
  8. Blender Foundation,Blender 5.0 手册,“OpenColorIO”——关于共享 OCIO 配置和宿主应用集成的独立下游文档。
  9. CVE Program,CVE-2026-42450——包含独立 CISA SSVC 补充信息、受影响版本界限和发布时间线的正式漏洞记录。
  10. SUSE,“CVE-2026-42450”——下游严重性评估和已修复的 OpenSUSE Tumbleweed 软件包版本。
  11. Erwin Verbruggen,“Colour grading with Scratch”,Wikimedia Commons——墨西哥国家电影资料馆照片的来源、日期、尺寸和出处信息。
Previous MATLAB 迁移到 Octave:先建立答案集,再处理语法

Recommended In oss

Matched by subject and format