深入分析图形渲染库精度问题引发的安全漏洞(下篇)
字数 1193 2025-08-20 18:17:48

图形渲染库精度问题引发的安全漏洞分析

概述

本文深入分析了图形渲染库中由于精度问题引发的安全漏洞,重点探讨了Skia和SwiftShader图形库中的精度误差问题。这些漏洞可能导致越界内存访问,进而引发安全风险。

浮点精度误差问题

样条线转换为线段时的浮点精度误差

在绘制路径时,Skia会将非线性曲线(圆锥曲线、二次和三次样条)转换为线段,这一转换过程容易受到浮点精度误差的影响。

三次样条转换过程

  1. 系数计算

    fA = P3 + three * (P1 - P2) - P0;
    fB = three * (P2 - times_2(P1) + P0);
    fC = three * (P1 - P0);
    fD = P0;
    
  2. 线段点计算

    const Sk2s dt(SK_Scalar1 / lines);
    Sk2s t(0);
    Sk2s A = coeff.fA;
    Sk2s B = coeff.fB;
    Sk2s C = coeff.fC;
    Sk2s D = coeff.fD;
    
    for (int i = 1; i < lines; ++i) {
        t = t + dt;
        Sk2s p = ((A * t + B) * t + C) * t + D;
        p.store(&tmp[i]);
    }
    

精度误差示例

对于绘图区域宽度为1000像素的情况,考虑以下坐标:

p0 = 1.501923
p1 = 998.468811
p2 = 998.998779
p3 = 999.000000

计算得到的系数:

a = 995.908203
b = -2989.310547
c = 2990.900879
d = 1.501923

使用512个线段逼近时,部分x坐标结果:

511 : 999.000244  // 超出安全区域

更大绘图区域的影响

对于32767像素的绘图区域(Chrome最大画布尺寸),考虑以下点:

p0 = 1.7490234375
p1 = 32765.9902343750
p2 = 32766.000000
p3 = 32766.000000

部分逼近结果:

511 : 32766.015625  // 明显越界

缓解措施:SkDrawTiler将大于8191x8191像素的图像拆分为多个图块,有效限制了精度误差的影响范围。

整数精度误差问题

样条线转换为线段时的整数精度误差

在填充路径时,SkCubicEdge::setCubicWithoutUpdate中的定点运算可能出现精度误差。

关键计算过程

SkFixed B = SkFDot6UpShift(3 * (x1 - x0), upShift);
SkFixed C = SkFDot6UpShift(3 * (x0 - x1 - x1 + x2), upShift);
SkFixed D = SkFDot6UpShift(x3 + 3 * (x1 - x2) - x0, upShift);

fCx = SkFDot6ToFixed(x0);
fCDx = B + (C >> shift) + (D >> 2 * shift);  // 问题所在
fCDDx = 2 * C + (3 * D >> (shift - 1));
fCDDDx = 3 * D >> (shift - 1);

精度误差示例

输入值:

x0 = -30
x1 = -31
x2 = -31
x3 = -31

计算参数:

B = -192
C = 192
D = -64
fCx = -30720
fCDx = -190  // 应为-189.015

线段逼近结果(部分):

35 : -0.484421  // 小于最小输入点-0.484375
...
64 : -0.488846

转换为SkFDot6类型后:

-31747 (SkFixed) >> 10 → -32 (SkFDot6, 即-0.5)

安全影响

  1. 内存访问模式

    • y=-1或y=height:堆越界写
    • y=0且x=-1:堆下溢1像素
    • x=width且y=height-1:堆溢出1像素
    • y>0且x=-1:像素"溢出"到上一图像行
    • x=height且y<height-1:像素"溢出"到下一图像行
  2. SkARGB32_Shader_Blitter问题

    • 分配与单行图像大小相同的临时缓冲区
    • 从x=-1到x=width-1渲染时,会写入width+1像素,导致缓冲区溢出

触发条件

  • 必须使用SVG图像并设置shape-rendering="crispEdges"来关闭抗锯齿
  • 需要包含linearGradient元素以选择SkARGB32_Shader_Blitter

修复方案

Skia通过增加kConservativeRoundBias值来修复这些精度问题,该偏差值足以覆盖已知的最大精度误差。

预防措施

  1. 浮点运算使用准则

    • 对安全性敏感的计算避免使用浮点运算
    • 必须使用时,确保最大精度误差在安全范围内
    • 考虑使用区间运算确定最大精度误差
    • 对计算结果而非输入进行安全检查
  2. 整数运算注意事项

    • 密切关注降低精度的运算(除法、右移)
    • 考虑使用更高精度的中间表示
  3. 漏洞发现方法

    • 源代码人工审计
    • 针对接近图像边界的值进行模糊测试
    • 对可疑代码区域进行暴力遍历测试

结论

图形渲染库中的精度问题可能导致严重的安全漏洞。开发者需要特别注意浮点和整数运算中的精度误差,特别是在处理图形边界时。通过合理的设计和严格的安全检查,可以有效地预防这类问题的发生。

图形渲染库精度问题引发的安全漏洞分析 概述 本文深入分析了图形渲染库中由于精度问题引发的安全漏洞,重点探讨了Skia和SwiftShader图形库中的精度误差问题。这些漏洞可能导致越界内存访问,进而引发安全风险。 浮点精度误差问题 样条线转换为线段时的浮点精度误差 在绘制路径时,Skia会将非线性曲线(圆锥曲线、二次和三次样条)转换为线段,这一转换过程容易受到浮点精度误差的影响。 三次样条转换过程 系数计算 : 线段点计算 : 精度误差示例 对于绘图区域宽度为1000像素的情况,考虑以下坐标: 计算得到的系数: 使用512个线段逼近时,部分x坐标结果: 更大绘图区域的影响 对于32767像素的绘图区域(Chrome最大画布尺寸),考虑以下点: 部分逼近结果: 缓解措施 :SkDrawTiler将大于8191x8191像素的图像拆分为多个图块,有效限制了精度误差的影响范围。 整数精度误差问题 样条线转换为线段时的整数精度误差 在填充路径时,SkCubicEdge::setCubicWithoutUpdate中的定点运算可能出现精度误差。 关键计算过程 精度误差示例 输入值: 计算参数: 线段逼近结果(部分): 转换为SkFDot6类型后: 安全影响 内存访问模式 : y=-1或y=height:堆越界写 y=0且x=-1:堆下溢1像素 x=width且y=height-1:堆溢出1像素 y>0且x=-1:像素"溢出"到上一图像行 x=height且y <height-1:像素"溢出"到下一图像行 SkARGB32_ Shader_ Blitter问题 : 分配与单行图像大小相同的临时缓冲区 从x=-1到x=width-1渲染时,会写入width+1像素,导致缓冲区溢出 触发条件 必须使用SVG图像并设置 shape-rendering="crispEdges" 来关闭抗锯齿 需要包含 linearGradient 元素以选择SkARGB32_ Shader_ Blitter 修复方案 Skia通过增加 kConservativeRoundBias 值来修复这些精度问题,该偏差值足以覆盖已知的最大精度误差。 预防措施 浮点运算使用准则 : 对安全性敏感的计算避免使用浮点运算 必须使用时,确保最大精度误差在安全范围内 考虑使用区间运算确定最大精度误差 对计算结果而非输入进行安全检查 整数运算注意事项 : 密切关注降低精度的运算(除法、右移) 考虑使用更高精度的中间表示 漏洞发现方法 : 源代码人工审计 针对接近图像边界的值进行模糊测试 对可疑代码区域进行暴力遍历测试 结论 图形渲染库中的精度问题可能导致严重的安全漏洞。开发者需要特别注意浮点和整数运算中的精度误差,特别是在处理图形边界时。通过合理的设计和严格的安全检查,可以有效地预防这类问题的发生。