部署安全缓解措施面临的挑战:ClangCFI与CFGuard的实践对比

本文详细记录了在osquery项目中应用控制流完整性(CFI)安全缓解措施的过程,对比了ClangCFI和CFGuard两种实现方案的严格性、开发成本与易用性差异,揭示了安全增强与工程实践之间的重要权衡。

计划实施

我们原计划简单明了:为Windows版osquery启用CFGuard,为Linux版启用ClangCFI。通过对比测试套件结果进行量化评估,最终将补丁贡献给osquery代码库,实现双赢——既产出技术博客又增强安全性。

严格性对比

ClangCFI在安全性上更为严格:

  • 对每个间接调用,ClangCFI允许的目标地址更少(图1示例)
  • 执行更全面的错误检测(如类型转换检查、虚方法调用目标验证等)
  • 要求全程序分析,因此必须满足:
    1. 所有链接对象和静态库都需启用CFI
    2. 必须启用链接时优化(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代码共存

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计