计划实施
我们原计划简单明了:为Windows版osquery启用CFGuard,为Linux版启用ClangCFI。通过对比测试套件结果进行量化评估,最终将补丁贡献给osquery代码库,实现双赢——既产出技术博客又增强安全性。
严格性对比
ClangCFI在安全性上更为严格:
- 对每个间接调用,ClangCFI允许的目标地址更少(图1示例)
- 执行更全面的错误检测(如类型转换检查、虚方法调用目标验证等)
- 要求全程序分析,因此必须满足:
- 所有链接对象和静态库都需启用CFI
- 必须启用链接时优化(LTO)
CFGuard则采用更宽松的验证标准:
- 仅需验证间接调用目标是否为合法函数入口点
- 支持渐进式部署,允许混合使用受保护和未受保护的代码模块
- 动态链接库(DSO/DLL)完全兼容
工程实践挑战
ClangCFI的全有或全无特性:
- 必须为整个依赖树启用CFI(包括libc++等深层依赖)
- 链接器不会检查CFI一致性,但运行时可能失败(表1展示合法链接组合)
代码兼容性问题: 尝试为strongSwan启用ClangCFI时,其C语言OOP系统因类型签名不匹配触发严格检查。虽然技术上ClangCFI正确,但实际代码中存在大量不符合标准的模式。CFI黑名单功能在此场景下几乎需禁用所有检查点,失去安全意义。
结论
从安全角度看,ClangCFI确实优于CFGuard——更严格的检查、全程序保护、更多运行时验证。Google Chrome团队已成功实践该方案。但增强安全的代价是:
- 需要大量开发时间投入
- 必须进行严格测试
- 对现有代码库改造难度大
而CFGuard的灵活性使其能快速应用于现有项目。最终我们的Windows版osquery已实装CFGuard,Linux版ClangCFI仍在攻坚中。这种对比深刻揭示了安全措施在理想与现实之间的关键权衡。
[1] 技术细节补充:CFGuard实际也存在例外情况,如某些被抑制的函数入口点仍属非法目标
[2] 根据Evgeniy Stepanov的解释,非CFI代码中的函数若仅被直接调用仍可混合链接
[3] 官方文档明确允许混合CFG/非CFG代码共存