RUSTSEC-2026-0311:latex-rust 中的漏洞
受影响版本的 latex-rust 中,解析器和排版引擎会随嵌套层级无限递归,没有任何限制。深度嵌套的输入(如 \frac{1}{…}、花括号、\sqrt{…}、\left( 或嵌套成百上千层的上标)会耗尽调用栈。
Rust 中的栈溢出会直接中止进程。它不是 panic,因此无法通过 catch_unwind 捕获。凡是渲染来自不可信输入的 LaTeX 的程序,都可能被一小段字符串终止。在 8 MiB 栈的 release 构建下,700 层嵌套的 \frac{1}{…}(约 7 KB 输入)即可让 1.0.4 版本中止,10,000 层嵌套花括号(约 20 KB)同样如此。栈更小或使用 debug 构建时,触发阈值更低:在 debug 构建的 2 MiB 线程栈上,约 35 层嵌套分数就足够了。
let mut src = String::from("1");
for _ in 0..700 {
src = format!("\\frac{{1}}{{{src}}}");
}
let _ = latex_rust::parse(&src); // 栈溢出,进程中止
修复版本在解析器和 layout 中统计嵌套深度,并拒绝嵌套超过 32 层的输入。parse、parse_with_colors 及各 latex_to_* 函数会返回 ParseError::Malformed("input nests deeper than 32 levels"),而对手工构建的树调用 layout 则返回 Error::Unsupported { what: "tree nests deeper than 32 levels" }。计数按解析器递归层数计算,一个花括号参数占两层,因此该限制允许 15 层嵌套的 \frac、\sqrt 或 x^{…},以及 31 层嵌套的分组、\left…\right 对或环境。在优化构建下,拒绝超限输入只需约 100 KiB 的栈空间。
1.0.5 版本修复了此问题,没有任何 API 变更,可直接替换 1.0.4;用 cargo update -p latex-rust 升级即可。它同时包含 2.0.0 的渲染修复,因此渲染结果与 1.0.4 有所不同。2.0.0 和 2.0.1 包含同样的修复,限制和错误信息完全相同,但相对 1.x 有破坏性 API 变更,并允许调用方通过 ParseOptions 和 layout_with_max_depth 调整该限制。
本公告依据 CC0-1.0 许可发布。