henryhchchc/lsp-fuzz

GitHub: henryhchchc/lsp-fuzz

LSPFuzz 是基于 LibAFL 实现的灰盒混合模糊测试工具,通过自动生成测试用例来发现语言服务器中的 bug 和崩溃。

Stars: 13 | Forks: 1

# LSPFuzz: Hunting Bugs in Language Servers LSPFuzz 是一个灰盒混合 fuzzer,用于为 [Language Servers](https://microsoft.github.io/language-server-protocol/) 生成测试用例。 它是基于 [LibAFL](https://github.com/AFLplusplus/LibAFL) 实现的。 ## 这是什么? 听起来很熟悉?理应如此!即使你没有任何不当操作,Language Server 中的 bug 也可能导致你的开发工作流中断。LSPFuzz 旨在自动发现此类 bug,避免它们被交付给你。 ## 技术细节 LSPFuzz 配备了一个两阶段的 mutation pipeline,能够生成有效且多样的输入,以触发 LSP Server 中各种分析例程。 要了解更多关于其工作原理的信息,请查看以下研究论文: Hengcheng Zhu, Songqiang Chen, Valerio Terragni, Lili Wei, Yepang Liu, Jiarong Wu, and Shing-Chi Cheung. **LSPFuzz: Hunting Bugs in Language Servers.** 刊于 _Proceedings of the 40th IEEE/ACM International Conference on Automated Software Engineering._ 韩国首尔。2025 年 11 月。 [🔗 DOI](https://doi.org/10.1109/ASE63991.2025.00183) | [🎤 会议](https://conf.researchr.org/details/ase-2025/ase-2025-papers/203/LSPFuzz-Hunting-Bugs-in-Language-Servers) | [📄 预印本](https://scholar.henryhc.net/files/publications/2025/ASE2025-LSPFuzz.pdf) | [📦 Artifacts](https://doi.org/10.5281/zenodo.17052142) 如果你将 LSPFuzz 用于学术目的,请引用上述论文。 用于开展论文实验的代码快照可以在 [ase25-major-revision](https://github.com/henryhchchc/lsp-fuzz/releases/tag/ase25-major-revision) tag 中找到。 ## 用法 ### 准备工作 1. 准备一个与 [AFL++](https://github.com/AFLplusplus/AFLplusplus) 兼容的 fuzz target。 强烈建议使用 [LTO mode](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.lto.md) 和 [persistent mode](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md)。 以下是 fuzz target 的注释模板: #include "your_header_file.h" #ifndef __AFL_FUZZ_TESTCASE_LEN // The following definitions allow compilation without the AFL++ compiler. ssize_t fuzz_len; #define __AFL_FUZZ_TESTCASE_LEN fuzz_len const uint8_t fuzz_buf[1024000]; #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf #define __AFL_FUZZ_INIT() void sync(void); #define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0) #define __AFL_INIT() sync() #endif __AFL_FUZZ_INIT(); int main(int argc, const char* argv[]) { #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif // [Initialization] // Perform one-time initialization for the target LSP server. // Or call `LLVMFuzzerInitialize(argc, argv)` here. const uint8_t *buf = __AFL_FUZZ_TESTCASE_BUF; while (__AFL_LOOP(10000)) { ssize_t len = __AFL_FUZZ_TESTCASE_LEN; // [Input Processing] // Process an input here: // 1. Read `len` bytes from `buf` for LSP inputs, as if they were read from `stdin`. // 2. Process the LSP inputs. Note that the input contains the `Content-Length` header. // 3. Release resources and reset states. // Or call `LLVMFuzzerTestOneInput(buf, len)` here. } return 0; } 2. 获取 coverage map 大小: AFL_DUMP_MAP_SIZE=1 ./fuzz-target 3. 挖掘用于代码生成的代码片段: lsp-fuzz-cli mine-code-fragments \ --search-directory \ # Directory containing code files of the target language for the LSP servers --output # File to store the mined code fragments ### 开始 Fuzzing ``` lsp-fuzz-cli fuzz \ --state \ # Directory to store the fuzzing state (e.g., generated inputs, found crashes) --lsp-executable \ # Executable file of the LSP server fuzz target --language-fragments Language=\ # Comma-separated list of files containing the mined code fragments, (e.g., `C=c.frag,CPlusPlus=cpp.frag`) --coverage-map-size \ # Size of the coverage map to use for coverage-guided fuzzing --time-budget 24 # Time budget for fuzzing in hours ``` 要了解更多关于选项的信息,请运行 `lsp-fuzz-cli fuzz --help`。 ### 重现检测到的崩溃 1. 导出生成的触发崩溃的输入: lsp-fuzz-cli export \ --input /solutions \ # Directory containing the generated crash-triggering inputs --output # Directory to store the exported crash-triggering inputs `` 的内容将被组织如下: ├── │ ├── workspace │ │ ├── file1.txt │ │ └── file2.txt │ └── requests │ ├── message_0001 │ └── message_0002 ├── │ ├── workspace │ │ ├── file1.txt │ │ └── file2.txt │ └── requests │ ├── message_0001 │ └── message_0002 └── ... 每个 `` 目录代表 LSPFuzz 生成的一个唯一输入。 在每个 `` 目录中,有两个子目录:`workspace` 和 `requests`。 `workspace` 目录包含代码文件,`requests` 目录包含在 fuzzing 期间发送给 LSP server 的 LSP 请求。 2. 将导出的输入提供给 LSP server: 要重现崩溃,请 `cd` 到包含导出输入的目录。 cat requests/* | ./target-lsp-server 请注意,`target-lsp-server` 是实际接受测试的 LSP server,而不是 fuzz target。 确保它从 `stdin` 读取请求,并且 CLI 选项已正确设置。 为了重现被 sanitizers 捕获的 bug,编译 `target-lsp-server` 时应启用 sanitizers。 ## 许可证 LSPFuzz 在 MIT 许可证下发布。详情请参阅 [LICENSE](./LICENSE) 文件。 遵循开放科学政策,研究论文和 artifact 公开发布。
标签:LibAFL, 代码安全, 可视化界面, 测试用例生成, 漏洞枚举, 语言服务器协议, 通知系统