一个仅 65 字节的模型文件就能让流行的 Llama CPP 推理引擎戛然而止。这个极小的负载在解析器内部触发了除以零的操作,导致 SIGFPE 崩溃。
为什么这次崩溃很重要
问题出在哪里
解析器将模型元数据读取到 C++ 结构体中,并检查每个张量(tensor)维度是否为“非负”。零满足该条件,因此检查通过。紧接着的下一行代码在计算中使用该维度作为除数,而该计算假设该值是正数。当维度为零时,除法操作会抛出浮点异常 (SIGFPE) 并终止程序。
验证过程仅覆盖了所需不变性(invariant)的一半:它拦截了负值,但忽略了零,而零对于随后的算术运算同样是不安全的。
开发者应该怎么做
- 像对待二进制文件一样对待模型文件。 加载模型会将原始字节解析为内存结构,这是典型的边界情况,未经验证的数据可能会导致进程崩溃甚至引发更严重的后果。
- 避免部分检查。 仅覆盖所需不变性一部分的条件会给人一种虚假的安全感。在这里,“非负”是不够的;代码需要的是“正数”。
- 在每次检查后质疑假设。 当出现边界测试时,请验证后续代码是否依赖于更严格的属性。
- 使用模糊测试(fuzzing)工具。 作者通过运行带有 AddressSanitizer 的 libFuzzer 发现了这个漏洞,该工具可以对输入进行变异并标记诸如除以零之类的非法操作。
修复是如何应用的
修复方案增加了一个保护机制,当维度等于零时跳过溢出计算。这个微小的条件判断在消除崩溃路径的同时,保留了对合法零大小张量(用于某些模型变体中的可选功能)的支持。
启示: 一个仅 65 字节的文件就能关闭一个广泛部署的推理引擎;彻底的验证和系统的模糊测试才能确保模型加载器的安全。
来源:https://dev.to/harrisonsec/your-model-file-is-untrusted-input-1eap
