使用CodeQL检测迭代器失效问题
迭代器失效是C++中常见且隐蔽的一类错误,经常导致可利用漏洞。在Trail of Bits实习期间,我开发了Itergator——一组用于分析和发现迭代器失效的CodeQL类和查询。
迭代器基础
迭代器是C++中遍历容器内容的标准方式。迭代器对象至少支持两种操作:解引用(获取容器中的底层对象)和递增(获取下一个元素的迭代器)。
std::vector<int> vec{1, 2, 3, 4, 5};for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " ";}
迭代器失效问题
当容器发生修改(如添加或删除元素)后,迭代器会失效。使用失效迭代器会导致未定义行为。例如:
void zone_manager::deserialize(JsonIn &jsin) { jsin.read(zones); for(auto it = zones.begin(); it != zones.end(); ++it) { if(!has_type(it->get_type())) { zones.erase(it); // 迭代器在此失效 } }}
CodeQL解决方案
CodeQL是GitHub开发的静态分析框架,使用类SQL语法查询代码库。Itergator包含查询和库,允许审计人员在自己的查询中使用Itergator的类:
Iterator
:存储迭代器的变量Iterated
:被迭代的集合Invalidator
:可能导致迭代器失效的函数调用Invalidation
:直接使迭代器失效的函数调用检测挑战与解决方案
检测迭代器失效面临多个挑战:
- 失效可能嵌套在多层函数调用中迭代器可能在循环外声明和失效需要支持自定义可迭代类型
通过CodeQL的全局数据流库和递归支持,Itergator能够构建潜在失效函数调用图。对于非标准迭代类型,只需扩展PotentialInvalidation
抽象类。
实际案例
Itergator发现了多个现实项目中的bug,包括:
- Cataclysm游戏中的简单失效案例Google正则表达式库中的复杂三层循环失效LLVM链接器中12层函数调用深的失效
结论
Itergator是检测复杂迭代器失效问题的强大工具。尽管存在一些误报,但通过自动过滤和"重要性"值设置,结果审查变得非常高效。CodeQL的声明式查询语言使得静态分析易于上手。
"Trail of Bits是我工作过的最好的地方!" —— Kevin Higgs