devdanzin/lafleur
GitHub: devdanzin/lafleur
面向 CPython 实验性 JIT 编译器的覆盖率引导进化模糊测试工具,用于发现崩溃、正确性错误和挂起问题。
Stars: 21 | Forks: 4
# lafleur
[](https://github.com/devdanzin/lafleur/actions)
[](https://pypi.org/project/lafleur/
[](https://www.python.org/)
[](https://www.gnu.org/licenses/gpl-2.0)
CPython JIT 编译器的反馈驱动进化模糊测试工具。
`lafleur` 是一个专用的模糊测试工具,旨在发现 CPython 实验性 JIT 编译器中的崩溃、正确性错误和挂起。与随机生成代码的传统模糊测试工具不同,`lafleur` 采用覆盖率引导的进化方法。它执行测试用例,通过分析详细的跟踪日志来观察其对 JIT 行为的影响,并利用该反馈来指导其变异,从而随着时间推移变得越来越善于发现有趣的代码路径。
这个名字来源于法语表达 *la fleur au fusil*,捕捉了项目启动时的精神。`lafleur` 最初是 Victor Stinner 创建的 [fusil](https://github.com/devdanzin/fusil) 项目中的一个高级功能集,后来作为一个独立工具分离出来。
## 功能特性
* **覆盖率引导:** 使用有状态的 uop 边覆盖率来跟踪 JIT 在跟踪、优化和执行状态下的行为,区分在新的 JIT 状态中发现边与发现真正新颖的边。
* **60 多种 JIT 特定变异器:** 一个针对特定 JIT 弱点的 AST 转换库 —— 类型推测、内联缓存、守卫处理、闭包单元、帧内省和稀有事件触发器。
* **自适应学习:** 一个 epsilon-greedy 变异引擎,跟踪哪些变异器发现了新的覆盖率并动态聚焦于最有效的策略,通过衰减分数来偏向最近成功的技术。
* **会话模糊测试:** 在共享进程中与“污染”脚本一起执行脚本,以压力测试 JIT 状态持久性、缓存污染和内存布局 —— 发现隔离执行会遗漏的深层、依赖状态的错误。
* **JIT 内省:** 使用 `ctypes` 在运行时检查 CPython 内部的 `_PyExecutorObject` 结构体,提取退出密度、僵尸跟踪计数和布隆过滤器状态,以奖励引发 JIT 不稳定性的变异。
* **智能调度:** 采用多因素评分系统来优先考虑快速、小型且发现了稀有或富饶代码路径的测试用例。
* **活动工具链:** 监控单个实例,将多核活动聚合到仪表板中,并使用链接到 GitHub 问题的 SQLite 注册表对崩溃进行分类。
## 安装和设置
`lafleur` 需要特定的 CPython 构建环境。请仔细遵循以下步骤。
### 步骤 1:构建启用 JIT 的 CPython
`lafleur` 必须在 **启用了实验性 JIT 编译器的 CPython 调试构建** 上运行。
1. **克隆 CPython:**
git clone https://github.com/python/cpython.git
cd cpython
2. **配置和构建(第一步):**
./configure --with-pydebug --enable-experimental-jit
make -j$(nproc)
3. **创建虚拟环境:**
./python -m venv ~/venvs/lafleur_venv
### 步骤 2:安装 `lafleur` 并调整 JIT
1. **激活您的虚拟环境:**
source ~/venvs/lafleur_venv/bin/activate
2. **从源码安装 `lafleur`(推荐):**
git clone https://github.com/devdanzin/lafleur.git
cd lafleur
pip install -e .
可编辑安装(`-e`)允许您通过 `git pull` 保持更新,并且是用户和开发者的推荐路径。虽然 [PyPI 上也提供](https://pypi.org/project/lafleur/)了发布版(`pip install lafleur`),但可能落后于最新的开发版本。
3. **调整 JIT:** 运行调整脚本,指向您的 CPython 源目录。这会降低 CPython C 头文件中的 `JIT_THRESHOLD` 和 `trace_stack_size`,使 JIT 更早编译并使用更浅的跟踪堆栈,这非常适合模糊测试。
lafleur-jit-tweak /path/to/your/cpython
4. **重新构建 CPython** 以应用调整后的设置:
cd /path/to/your/cpython
make -j$(nproc)
### 步骤 3:填充语料库(可选)
`lafleur` 可以使用经典的 `fusil` 模糊测试工具生成一组初始的有趣种子文件。这是推荐的,但不是必需的。
1. **安装 `fusil`:**
git clone https://github.com/devdanzin/fusil.git
cd fusil
pip install .
如果您不想安装 `fusil`,可以在您的工作目录中创建一个名为 `corpus/jit_interesting_tests/` 的目录,并将您自己手工编写的 Python 种子文件放入其中。
## 使用方法
安装完成后,您可以从任何目录运行 `lafleur`。它将在当前工作目录中创建其输出子目录(`corpus/`、`crashes/` 等)。别忘了先激活您的虚拟环境。
### 基本用法(恢复运行)
如果语料库已经存在,此命令将加载状态并恢复模糊测试会话。
```
lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded
```
### 填充新语料库
使用 `--min-corpus-files` 调用 `fusil` 填充器,直到语料库在启动主进化循环之前至少有 20 个文件。
```
lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded --min-corpus-files 20
```
### 会话模糊测试(有状态 JIT 测试)
使用 `--session-fuzz` 在共享进程中执行脚本。这会跨脚本边界保留 JIT 状态,从而实现“热 JIT”攻击,即污染脚本在变异子代运行之前对缓存和内存布局施加压力。
```
lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded --session-fuzz
```
### 针对特定的 CPython 构建
默认情况下,`lafleur` 使用您活动虚拟环境中的 Python 解释器。使用 `--target-python` 来模糊测试不同的构建。
```
lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded --target-python /path/to/cpython/python
```
### 其他选项
| 选项 | 描述 |
|--------|-------------|
| `--runs N` | 将每个变异的测试用例运行 N 次(对非确定性错误有用) |
| `--dynamic-runs` | 根据父分数自动调整运行次数 |
| `--timeout N` | 设置脚本执行超时时间(秒)(默认值:10) |
| `--instance-name NAME` | 此模糊测试实例的人类可读名称 |
| `--deepening-probability P` | 深度优先与会话的概率(默认值:0.2) |
| `--prune-corpus` | 分析并报告冗余的语料库文件,然后退出 |
| `--keep-tmp-logs` | 保留临时日志文件以进行调试 |
### 诊断模式
用于快速冒烟测试和变异器开发:
```
# 有界冒烟测试(3 个会话,每个 2 个 mutation,可复现)
python -m lafleur --max-sessions 3 --max-mutations-per-session 2 --seed 42
# 在 dry-run 模式下测试特定 mutator
python -m lafleur --mutators GCInjector --strategy spam \
--max-sessions 1 --max-mutations-per-session 5 --dry-run --keep-children
# 列出所有可用的 mutator
python -m lafleur --list-mutators
```
有关详细信息,请参阅 [诊断模式文档](doc/dev/09_diagnostic_mode.md)。
## 分析与分类
`lafleur` 包含一套工具,用于监控模糊测试进度、聚合活动结果以及长期管理崩溃发现。
| 工具 | 用途 |
|------|---------|
| **`lafleur-report`** | 检查正在运行的模糊测试器的脉搏。为单个实例生成健康状况、覆盖率和崩溃摘要。 |
| **`lafleur-campaign`** | 将 50 多个核心的结果聚合到一个仪表板中。对崩溃进行去重,生成队列范围的指标,并生成 HTML 报告。 |
| **`lafleur-triage`** | 使用内置的 SQLite 数据库跟踪回归和已知问题。将崩溃链接到 GitHub 问题并管理其生命周期。 |
### 快速示例
```
# 单实例报告
lafleur-report /path/to/instance
# 带 HTML 输出的 Campaign 仪表板
lafleur-campaign runs/ --html report.html --registry crashes.db
# 交互式 Crash 分类
lafleur-triage interactive
```
有关详细用法,请参阅[分析与分类工作流](docs/TOOLING.md)文档。
## 解读结果
模糊测试运行最重要的发现将保存在两个目录中:
* **`crashes/`**:包含导致硬崩溃(例如 SegFault)或引发严重错误的脚本。每个 `.py` 文件都伴有一个包含崩溃输出的 `.log` 文件。
* **`timeouts/`**:包含运行时间过长(默认值 > 10 秒)的脚本,通常表示无限循环错误。
## 文档
要全面了解 `lafleur` 的内部原理,请参阅 [开发者文档](doc/dev/00_index.md) —— 这是一个包含 8 个文档的系列,涵盖了架构、进化循环、覆盖率信号、变异引擎、状态格式、设置、扩展和测试。
## 贡献与提交问题
`lafleur` 是一个开源项目,欢迎贡献。有关完整的贡献者指南,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
要提交错误报告或功能请求,请使用项目的 [GitHub Issues](https://github.com/devdanzin/lafleur/issues) 页面。提交由 `lafleur` 发现的 JIT 错误时,请包含:
1. 崩溃的测试用例(`.py` 文件)。
2. 完整的日志文件(`.log`)。
3. 您正在模糊测试的 CPython 版本的提交哈希(可以使用 `python -VV` 获取)。
标签:AST变换, CPython, DNS解析, Fuzzing, JIT编译器, Python, 代码安全, 即时编译器, 多模态安全, 安全测试, 开源项目, 异常检测, 攻击性安全, 无后门, 测试工具, 漏洞枚举, 自动化payload嵌入, 覆盖率引导, 软件开发, 进化算法