cargo-fuzz tutorial

一.安装

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);
    };
});




第五步 分析结果

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 注销 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 注销 /  更改 )

Connecting to %s