Prhub

#54935 [Security] Cap GLMGA video sampling to prevent request-driven resource exhaustion

原始 PR 作者 jperezdealgaba 合并时间 2026-09-04 20:02 文件变更 2 提交数 2 评论 6 代码增减 +60 / -3

执行摘要

为 GLMGA 视频后端添加采样上限,防止请求驱动的资源耗尽。

修复一个安全漏洞(GHSA-58v5-2m8f-94pr)。根据 PR body 描述,GLMGAVideoBackend.compute_frames_index_to_sample 计算 extract_t = min(int(duration * target_fps), max_frames),其中 target_fps 和 max_frames 均可通过请求级 media_io_kwargs 控制。当 total_frames_num < extract_t 时,列表推导式 range(extract_t) 会创建攻击者控制的、远超实际帧数的中间列表分配,造成拒绝服务风险。

此 PR 值得精读。它展示了如何为用户可控参数添加多层防御以防止资源耗尽攻击,模式清晰。但 CodeRabbit 关于中间列表分配的评论指出了一个尚未解决的性能/稳定性问题,值得关注。建议在后续 PR 中重构采样逻辑,直接生成有界索引。

讨论亮点

CodeRabbit 在 review 中提出了两个重要意见:

1) 在 vllm/multimodal/video.py 第 819 行指出,虽然 extract_t 被钳制,但循环仍会生成大量中间索引列表(在最终重采样前),建议重构采样逻辑以直接生成有界索引列表。
2) 在 tests/multimodal/test_video.py 第 1517 行指出,当前 test_class_cap_overrides_target_fps 测试无法区分 fps 上限和 _MAX_FRAMES 限制,建议使用更精确的测试用例。这两个建议均未被采纳,但 PR 作者 Isotr0py 在审批时表示“LGTM,可能需要在后续 PR 中重构以识别哪些 kwargs 可被运行时覆盖”,暗示了这些技术债务。

实现拆解

  1. 源码变更(vllm/multimodal/video.py):在 GLMGAVideoBackend 类中新增两个类级别常量:_MAX_FRAMES = 640 和 _MAX_FPS = 30。修改 compute_frames_index_to_sample 方法:将 target_fps 钳制到 min(target.fps, cls._MAX_FPS);将 max_frames 钳制到 min(kwargs.get("max_frames", cls._MAX_FRAMES), cls._MAX_FRAMES);在计算 extract_t 时,增加对 total_frames_num 的钳制 min(extract_t, max_frames, total_frames_num)。
  2. 测试配套(tests/multimodal/test_video.py):新增测试类 TestGLMGASamplingCaps,包含四个测试用例:test_extreme_values_bounded_by_total_frames(验证极端参数下索引数不超过实际帧数)、test_class_cap_overrides_kwargs_max_frames(验证类上限覆盖请求参数)、test_class_cap_overrides_target_fps(验证类上限覆盖请求 fps)、test_normal_operation_unchanged(验证正常功能不受影响)。
文件 模块 状态 重要度
vllm/multimodal/video.py 多模态视频 modified 6.48
tests/multimodal/test_video.py 多模态测试 modified 7.0

关键符号

GLMGAVideoBackend.compute_frames_index_to_sample

关键源码片段

vllm/multimodal/video.py core-logic

核心安全修复文件,为 GLMGAVideoBackend 添加了输入钳制常量和逻辑,防止资源耗尽。

# vllm/multimodal/video.py 中 GLMGAVideoBackend 类的关键变更
@VIDEO_LOADER_REGISTRY.register(
    "glmga",
    video_processor="GlmgaVideoProcessor",
)
class GLMGAVideoBackend(VideoBackend):
    # 新增类级别安全常量,防止请求参数导致资源耗尽
    _MAX_FRAMES: ClassVar[int] = 640
    _MAX_FPS: ClassVar[int] = 30
​
    @classmethod
    def compute_frames_index_to_sample(
        cls,
        source: VideoSourceMetadata,
        target: VideoTargetMetadata,
        **kwargs,
    ) -> list[int]:
        total_frames_num = source.total_frames_num
        duration = source.duration
        original_fps = source.original_fps
        # 将请求的 fps 钳制到类级别上限,防止创建过大中间列表
        target_fps = min(target.fps, cls._MAX_FPS)
        max_frame_idx = source.total_frames_num - 1
        # 将请求的 max_frames 钳制到类级别上限,双重保险
        max_frames = min(kwargs.get("max_frames", cls._MAX_FRAMES), cls._MAX_FRAMES)
​
        duration = duration or round(max_frame_idx / original_fps) + 1
​
        extract_t = int(duration * target_fps)
        # 关键安全修复:将 extract_t 同时钳制到 max_frames 和视频实际帧数
        # 这确保后续生成的索引列表不会超过视频实际内容,即使前两个钳制被绕过
        extract_t = min(extract_t, max_frames, total_frames_num)
        # ... 后续采样逻辑不变 ...
tests/multimodal/test_video.py test-coverage

新增回归测试类,专门验证安全修复的有效性和正常功能的兼容性。

# tests/multimodal/test_video.py 中新增的测试类
class TestGLMGASamplingCaps:
    """Regression tests for GHSA-58v5-2m8f-94pr: request-controlled fps
    and max_frames must not create intermediate allocations larger than
    the actual frame count."""
​
    @staticmethod
    def _source(
        total_frames: int, fps: float = 30.0, duration: float = 0
    ) -> VideoSourceMetadata:
        if duration == 0 and fps > 0 and total_frames > 1:
            duration = round((total_frames - 1) / fps) + 1
        return VideoSourceMetadata(total_frames, fps, duration)
​
    def test_extreme_values_bounded_by_total_frames(self):
        # 核心安全测试:2 帧视频,请求极大 fps 和 max_frames,确保索引数不超过 2
        source = self._source(total_frames=2, fps=2.0, duration=1.0)
        target = VideoTargetMetadata(num_frames=-1, fps=500_000, max_duration=-1)
        indices = GLMGAVideoBackend.compute_frames_index_to_sample(
            source,
            target,
            max_frames=500_000,
        )
        assert len(indices) <= 2
​
    def test_class_cap_overrides_kwargs_max_frames(self):
        # 验证 _MAX_FRAMES 类常量覆盖请求参数
        source = self._source(total_frames=10_000, fps=30.0)
        target = VideoTargetMetadata(num_frames=-1, fps=30, max_duration=-1)
        indices = GLMGAVideoBackend.compute_frames_index_to_sample(
            source,
            target,
            max_frames=100_000,
        )
        assert len(indices) <= GLMGAVideoBackend._MAX_FRAMES
​
    def test_class_cap_overrides_target_fps(self):
        # 验证 _MAX_FPS 类常量覆盖请求 fps
        source = self._source(total_frames=10_000, fps=30.0)
        target = VideoTargetMetadata(num_frames=-1, fps=500_000, max_duration=-1)
        indices = GLMGAVideoBackend.compute_frames_index_to_sample(
            source,
            target,
        )
        assert len(indices) <= GLMGAVideoBackend._MAX_FRAMES
​
    def test_normal_operation_unchanged(self):
        # 验证正常视频处理功能不受安全限制影响
        source = self._source(total_frames=1000, fps=30.0, duration=33.0)
        target = VideoTargetMetadata(num_frames=-1, fps=2, max_duration=-1)
        indices = GLMGAVideoBackend.compute_frames_index_to_sample(
            source,
            target,
        )
        assert 0 < len(indices) <= GLMGAVideoBackend._MAX_FRAMES
        assert all(0 <= idx < 1000 for idx in indices)

评论区精华

测试未能有效区分 fps 上限和帧数上限 测试

CodeRabbit 指出当前 `test_class_cap_overrides_target_fps` 测试无法区分 fps 上限(30)和 _MAX_FRAMES 上限(640),因为两者同时作用。建议使用更精确的测试用例(例如 10 秒、100 fps 的视频,期望 300 帧)。

结论:未采纳,测试保持不变。PR 作者在审批时暗示可能在后续 PR 中重构相关 kwargs 处理逻辑。 · 未解决

中间索引列表可能仍然过大 性能

CodeRabbit 指出,即使 `extract_t` 被钳制,采样循环(第 828-836 行)在 `total_frames_num` 很大且 `target_fps` 较低时,仍可能为每个视频帧都生成索引,导致中间列表分配过大。建议重构采样逻辑,直接生成有界索引列表。

结论:未采纳。这属于未解决的技术债务,可能在后续 PR 中优化。 · 未解决

风险与影响

  1. 功能回归风险:虽然新增了正常操作测试,但对现有使用 GLMGAVideoBackend 的用户或模型,如果其依赖超过 640 帧或 30 fps 的采样,行为将被强制限制,可能影响视频处理质量。
  2. 中间分配风险:如 CodeRabbit 指出,当 total_frames_num 远大于 extract_t 时,现有循环仍可能生成大量中间索引(尽管最终会缩减),但此次修复未解决此点。
  3. 兼容性风险:此修复为安全加固,属于必要变更,但可能影响一些边缘用例。
  1. 用户影响:所有使用 GLM-GA 视频处理的用户将受到采样上限约束,确保请求安全。
  2. 系统影响:增强了 vllm 多模态处理层的资源安全性,防止通过恶意视频请求导致服务拒绝。
  3. 团队影响:为处理类似资源控制问题提供了模式参考(类级别常量 + 多层钳制),但 CodeRabbit 的反馈指出了进一步优化的方向。
安全加固可能影响边缘用例 中间列表分配风险未完全解决

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论