一.安装
github: https://github.com/rust-fuzz/cargo-fuzz
安装: cargo install cargo-fuzz
➜ fuzzing cargo install cargo-fuzz
Updating https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git
index
Downloaded cargo-fuzz v0.10.0 (registry https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git
)
Downloaded 1 crate (30.5 KB) in 2.33s
Installing cargo-fuzz v0.10.0
……
Finished release [optimized] target(s) in 47.02s
Replacing /root/.cargo/bin/cargo-fuzz
Replaced package cargo-fuzz v0.8.0
with cargo-fuzz v0.10.0
(executable cargo-fuzz
)
➜ fuzzing cargo-fuzz
cargo-fuzz 0.10.0
A cargo
subcommand for using libFuzzer
! Easy to use! No need to recompile LLVM!
USAGE:
cargo-fuzz
FLAGS:
-h, –help Prints help information
-V, –version Prints version information
SUBCOMMANDS:
add Add a new fuzz target
build Build fuzz targets
cmin Minify a corpus
coverage Run program on the generated corpus and generate coverage information
fmt Print the std::fmt::Debug
output for an input
help Prints this message or the help of the given subcommand(s)
init Initialize the fuzz directory
list List all the existing fuzz targets
run Run a fuzz target
tmin Minify a test case
注意: cargo-fuzz 是集成了libfuzzer,libFuzzer依赖LLVM的,所以只能是x86-64的linux或者macos才可以,而且还需要C++编译器和C++11的支持。
用法
初始化: cargo fuzz init
- 添加目标: cargo fuzz add <target>
- 运行: cargo fuzz run <target>
- 打印测试用户输出
:cargo fuzz fmt <target> <input>
- 缩小到最小输出:
cargo fuzz tmin <target> <input>
- 缩小输入数据:
cargo fuzz cmin <target>
- 生成覆盖范围信息
: cargo fuzz coverage <target>
官方文档: https://rust-fuzz.github.io/book/cargo-fuzz.html
二.实战
我们随机选了一个好fuzzing的库,Human Time, 一个parser 时间的这种库。
crate: https://crates.io/crates/humantime
github: https://github.com/tailhook/humantime
文档: https://docs.rs/humantime/2.1.0/humantime/
第一步: 把项目clone到本地
git clone https://github.com/tailhook/humantime
我们可以看到,这个库自己是没有fuzz文件夹的,说明并没有做fuzzing
➜ humantime git:(master) ls
benches bulk.yaml Cargo.toml LICENSE-APACHE LICENSE-MIT README.md src vagga.yaml
第二步 : 项目初始化
进行项目文件夹执行
cargo fuzz init
可以看到,多了一个fuzz的文件夹
fuzz的文件夹结构:
➜ fuzz git:(master) ✗ tree
.
├── Cargo.toml
└── fuzz_targets
└── fuzz_target_1.rs
1 directory, 2 files
fuzz_target_1.rs的代码:
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
});
第三步,开始编写测试用例
我们查看文档,看看这个库的具体用法
https://docs.rs/humantime/2.1.0/humantime/fn.format_duration.html
#![no_main]
use libfuzzer_sys::fuzz_target;
use humantime::parse_duration;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
let _ = parse_duration(s);
};
});
我们把data变成字符串,看看parse_duration是怎么解析的。
第四步,运行
cargo fuzz list 可以列出所有的测试用例
➜ fuzz_targets git:(master) ✗ cargo fuzz list
fuzz_target_1
我们继续添加测试用例
#![no_main]
use libfuzzer_sys::fuzz_target;
use humantime::{parse_duration, parse_rfc3339, parse_rfc3339_weak};
fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
if let Ok(s) = std::str::from_utf8(data) {
let _ = parse_duration(s);
let _ = parse_rfc3339(s);
let _ = parse_rfc3339_weak(s);
};
});