从希望与梦想中创建LLVM检测器 - Trail of Bits博客
每年,Trail of Bits都会举办为期一个月的冬季实习项目(称为"winternship")。今年我们很高兴接待了4名实习生,他们参与了3个项目。本项目来自Carson Harmon,他是普渡大学的新毕业生,对编译器和系统工程感兴趣,现已成为我们研究实践部门的全职成员。
我最初计划在LLVM中实现动态指向分析(dynamic points-to analysis)作为我的冬季实习项目。指向分析可以告诉我们,在程序中给定地址或指针处内存中存储的数据类型,以及可能的内存分配位置。这很有用,因为它有助于评估静态分析的准确性,用额外事实增强静态分析,并提供关于某些对象创建时间和位置的上下文。
LLVM检测器基础设施为实现此类分析提供了天然的位置。检测器可以在编译时对程序进行插桩,并包含一个运行时支持库,该库具有libc实现、函数替换接口、内存和线程管理、操作系统特定的系统调用支持等功能。事实上,许多开发者经常使用的现有错误查找工具都是作为检测器实现的,包括:
- AddressSanitizer:识别无效的堆栈和堆访问、释放后使用和其他类型的内存访问错误
- MemorySanitizer:检测未初始化的读取
- LeakSanitizer:定位内存泄漏
- UndefinedBehaviorSanitizer:检测未定义行为(例如整数溢出和过度移位)
不幸的是,由于缺乏关于LLVM检测器的文档,我的指向分析没有取得很大进展。相反,我将提供LLVM的高级概述以及如何使用它来制作检测器,重述我在冬季实习期间经历的步骤。
如何编写自己的LLVM检测器
我首先查阅了Eli Bendersky的博客和GitHub仓库、Adrian Sampson博士的博客、EuroLLVM的会议记录以及LLVM的广泛工具链文档。我发现的一些信息已经过时,但它帮助确定了构建自己的检测器需要交互的模块。
编译器驱动是LLVM中所有模块之间的粘合剂;任何需要在模块之间传递的信息都通过驱动程序传递。构建检测器可能需要修改这些组件中的任意数量。我发现理解驱动程序设计对于系统开发很重要。
Clang前端、LLVM IR、compiler-rt和编译器驱动之间的高层关系
如果分析传递或检测器想要修改LLVM类型生成过程,它们需要修改驱动程序的代码生成过程。
Clang类型在代码生成过程中的数据流
驱动程序还负责调度和运行LLVM传递。LLVM传递修改IR以插入、删除或替换指令,这特别有用,因为它允许检测器修改指令和插入函数调用,而无需开发人员付出任何额外努力。驱动程序根据传递给前端的配置设置注册传递。检测器传递应该最后运行,因为驱动程序可能会运行优化传递、分析传递或其他可能影响您插桩的转换传递。
传递管理器和驱动程序之间的交互
最后,驱动程序负责链接检测器的运行时组件compiler-rt。Compiler-rt是一个库,为检测器提供了在执行期间与目标程序交互的能力。这种交互可以通过LLVM转换传递插入对compiler-rt中定义的函数的调用来实现,或者通过使用compiler-rt的函数钩子接口来实现。
转换传递和运行时组件之间的交互
制作自己的检测器
我创建了一个教程来帮助制作自己的检测器,其中包括预构建的测试检测器、关于开发和集成传递和运行时组件的分步指南,以及其他在LLVM上开发的有用资源。我认为冬季实习是在寒假学习新东西的好方法,我希望更多公司提供类似的项目。
如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News
页面内容
如何编写自己的LLVM检测器 制作自己的检测器 近期文章 非传统创新者奖学金 在您的PajaMAS中劫持多代理系统 我们构建了MCP一直需要的安全层 利用废弃硬件中的零日漏洞 Inside EthCC[8]:成为智能合约审计员 © 2025 Trail of Bits. 使用Hugo和Mainroad主题生成。