RPG:

 Rust Library Fuzzing with Pool-based Fuzz Target Generation and Generic Support

About RPG

    Rust libraries are ubiquitous in software development. Guaranteeing their correctness and reliability requires thorough analysis and testing. Fuzzing is a popular bug-finding solution, yet it requires writing fuzz targets for libraries. Recently, some automatic fuzz target generation methods have been proposed. However, two challenges remain:  (1) how to generate diverse API sequences that prioritize unsafe code and interactions to reveal bugs in Rust libraries; (2) how to provide support for the generic APIs and verify both syntactic and semantic validity of the fuzz targets to achieve a high coverage rate.

    In this paper, we propose RPG, an automatic fuzz target synthesis technique to support Rust library fuzzing. RPG uses a pool-based search to generate diverse and unsafe API sequences, and synthesizes fuzz targets with generic support and validity check. The experimental results demonstrate that RPG enhances both the quality of the generated fuzz targets and the bug-finding ability through pool-based search and generic support, substantially outperforming the state-of-the-art. Moreover, RPG has discovered 25 previously unknown bugs from 50 well-known Rust libraries available on Crates.io.

Workflow

    We propose a pool-based fuzz target generation for Rust libraries, namely RPG. The main workflow of RPG is illustrated in the following Figure, which consists of the following steps:

Tool

   We have made our experimental data set (50 Rust crates) and the source code of the tool prototype fully available to the public (https://zenodo.org/record/8202159), so that future researchers can reproduce our experiments.

Bug Found (25 new bugs)

 We have discovered 25 previously unknown bugs in popular Rust libraries. These bugs were not previously reported. We informed the maintainers, and the developers actively confirmed these bugs with our reports. We are confident that RPG is effective and viable in practice. 


Remarks on Bug Types:

# Bug 1:

Rust Crate: regex v1.5.4 (https://github.com/rust-lang/regex)

Bug location: src/exec.rs:702:28

Bug Type: arith

Buf Information: Program unexpected panic caused by index out of bound when indexing operation for text with Unanchored ty in Method ExecNoSync::find_literals

Original Bug Report: https://github.com/rust-lang/regex/issues/972

POC:

fn main () 

{

    let _local0 = regex::Regex::new("(\0\0\0\0\0\0\u{10}|\0\0\0\0\0)\0\0\0\0\0\0\0\0\0\u{10}|\0\0\0\0\0\0\0");

    let _local1_param0_helper1 = _local0.unwrap();

    let _local1 = regex::Regex::find_at(&(_local1_param0_helper1), "\0\u{4}\0*****\u{17}***************\0\0\0\0\0\0\0\0\0\0", 35184372153856);

    let _local2_param0_helper1 = _local1.unwrap();

    regex::Match::end(&(_local2_param0_helper1));

}

Interaction with developers:

# Bug 2:

Rust Crate: regex v1.5.4 (https://github.com/rust-lang/regex)

Bug location: regex/src/re_set.rs:419:1, and regex/src/re_trait.rs:23:23

Bug Type: arith

Buf Information: The function pos() is called by CaptureLocation::get. it calculate index out of bound, which cause a unexpected behavior.

Original Bug Report: https://github.com/rust-lang/regex/issues/950

POC:

fn main() 

{

    let pattern = "\n\n\n\n&;*****\0\u{2}**\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n****\u{f}*\u{19}\r.\u{19}";

    let group_index = 9944060567225171988;


    let re = regex::Regex::new(pattern).unwrap();

    let locs = re.capture_locations();

    dbg!(locs.get(group_index));

}

Interaction with developers:

# Bug 3:

Rust Crate: regex v1.5.4 (https://github.com/rust-lang/regex)

Bug location: regex:461:22

Bug Type: arith

Buf Information: Program unexpected panic caused by index out of bound when indexing operation for text with MatchType::DfaAnchoredReverse matched in Method ExecNoSync::shortest_match_at

Original Bug Report: https://github.com/rust-lang/regex/issues/972

POC:

fn main() 

{

    let _local0 = regex::RegexBuilder::new("$");

    let _local1 = regex::RegexBuilder::build(&(&_local0));

    let _local2_param0_helper1 = _local1.unwrap();

    regex::Regex::shortest_match_at(&(_local2_param0_helper1), "{S", 8897841259371199355);

}

Interaction with developers:


# Bug 4:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: src/format/scan.rs:173:43

Bug Type: utf-8

Buf Information: Program unexpected panic caused by not a char boundary when indexing operation in Method short_or_long_weekday

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    chrono::naive::NaiveDateTime::parse_from_str("\u{c}SUN\u{e}\u{3000}\0m@J\u{3000}\0\u{3000}\0m\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}\0SU\u{c}\u{c}",

"\u{c}\u{c}%A\u{c}\u{b}\0SUN\u{c}\u{c}\u{c}SUNN\u{c}\u{c}\u{c}SUN\u{c}\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}%a");

    let _local1 = chrono::offset::FixedOffset::east_opt(17367308);

    let _local2_param0_helper1 = _local1.unwrap();

    chrono::offset::Offset::fix(&(_local2_param0_helper1));

}

Interaction with developers:

# Bug 5:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: src/round.rs:231:67

Bug Type: arith

Buf Information: Program unexpected panic caused by substract overflow when delta_down less than 0 in Method DurationRound::duration_trunc

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp_opt(-4227854320, 1678774288);

    let _local1 = chrono::Duration::microseconds(-7019067213869040);

    let _local2_param0_helper1 = _local0.unwrap();

    chrono::DurationRound::duration_trunc(_local2_param0_helper1, _local1);

}

Interaction with developers:

# Bug 6:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: naïve/date.rs:1524:45

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method NaiveDate::with_month

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp(-8377300, 742391807);

    chrono::Datelike::with_month0(&(_local0), 4294967295);

    chrono::Datelike::with_month(&(_local0), 4294967295);

}

Interaction with developers:

.# Bug 7:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: naïve/date.rs:1524:45

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method NaiveDate::with_month

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp(-8377300, 742391807);

    chrono::Datelike::with_month0(&(_local0), 4294967295);

    chrono::Datelike::with_month(&(_local0), 4294967295);

}

Interaction with developers:

See Bug 4.

# Bug 8:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: naïve/date.rs:1562:43

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method NaiveDate::with_day

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp_opt(-754576364, 336909572);

    let _local1_param0_helper1 = _local0.unwrap();

    chrono::Datelike::with_day0(&(_local1_param0_helper1), 4294967295);

}

Interaction with developers:

See Bug 4.

# Bug 9:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: naive/datetime/mod.rs:479:21

Bug Type: arith

Buf Information: Program unexpected panic caused by multiple overflow in Method NaiveDateTime::timestamp_nanos

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp(-11676614656, 15282199);

    chrono::naive::NaiveDateTime::timestamp_nanos(&(&_local0));

}

Interaction with developers:

See Bug 5.

# Bug 10:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: round.rs:198:18

Bug Type: arith

Buf Information: Program unexpected panic caused by substract overflow when delta_down less than 0 in Method DurationRound::duration_round

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp_opt(320041586, 1920103021);

    let _local1 = chrono::Duration::nanoseconds(-8923838508697114584);

    let _local2_param0_helper1 = _local0.unwrap();

    chrono::DurationRound::duration_round(_local2_param0_helper1, _local1);

}

Interaction with developers:

See Bug 5.

# Bug 11:

Rust Crate: chrono v0.4.19 (https://github.com/chronotope/chrono)

Bug location: naïve/date.rs:1524:45

Bug Type: arith

Buf Information: Program unexpected panic caused by substract overflow when delta_down greater than 0 in Method DurationRound::duration_round

Original Bug Report: https://github.com/chronotope/chrono/issues/1010

POC:

fn main() 

{

    let _local0 = chrono::naive::NaiveDateTime::from_timestamp_opt(-2621440, 0);

    let _local1 = chrono::Duration::nanoseconds(-9223372036854771421);

    let _local2_param0_helper1 = _local0.unwrap();

    chrono::DurationRound::duration_round(_local2_param0_helper1, _local1);

}

Interaction with developers:

See Bug 5.

# Bug 12:

Rust Crate: bumpalo v3.9.1 (https://github.com/fitzgen/bumpalo)

Bug location: src/lib.rs:468:46

Bug Type: unwrap

Buf Information: Allocating too much initial capacity using with_capacity caused unwrap() LayoutError, resulting in panic.

Original Bug Report: https://github.com/fitzgen/bumpalo/issues/200

POC:

fn main() 

{

    let mut _local0 = bumpalo::Bump::with_capacity(10995706271387654244);

}

Interaction with developers:

# Bug 13:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:544:30

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method GraphemeCursor::is_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(18446742978509668351, 18446744073709551615, false);

    let _ = unicode_segmentation::GraphemeCursor::is_boundary(&mut (_local0), "t\u{7f}", 18446744073709551615);

}

Interaction with developers:

# Bug 14:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:406:17

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method GraphemeCursor::provide_context.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(18446707789825836799, 18446744073709551615, false);

    unicode_segmentation::GraphemeCursor::provide_context(&mut (_local0), "1", 18446744073709551615);

}

Interaction with developers:

See Bug 13.

# Bug 15:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:716:32

Bug Type: arith

Buf Information: Program unexpected panic caused by subtract overflow in Method GraphemeCursor::prev_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(5404402016221612875, 5425481077020773195, false);

    let _ = unicode_segmentation::GraphemeCursor::prev_boundary(&mut (_local0), "KKK", 5425512962414627659);

}

Interaction with developers:

See Bug 13.

# Bug 16:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:543:56

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method GraphemeCursor::is_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(18446744073709551615, 8502796096475496447, false);

    let _ = unicode_segmentation::GraphemeCursor::is_boundary(&mut (_local0), "\u{6dd}", 18446744073709551615);

}

Interaction with developers:

See Bug 13.

# Bug 17:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:634:30

Bug Type: arith

Buf Information: Program unexpected panic caused by subtract overflow in Method GraphemeCursor::next_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(5208492444341520456, 5208492444341520431, true);

    let _ = unicode_segmentation::GraphemeCursor::next_boundary(&mut (_local0), "HHHHHHHHHHHHH", 5208492589950978632);

}

Interaction with developers:

See Bug 13.

# Bug 18:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:642:17

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method GraphemeCursor::next_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(18446744073709551615, 16212958658533785599, false);

    let _ = unicode_segmentation::GraphemeCursor::next_boundary(&mut (_local0), "0", 18446744073709551615);

}

Interaction with developers:

See Bug 13.

# Bug 19:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:406:70

Bug Type: unwrap

Buf Information: Created an object with new() whose `pre_context_offset` is None and unwraped on it, resulting in panic.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(7812738666512280684, 7812738666512280684, true);

    unicode_segmentation::GraphemeCursor::provide_context(&mut (_local0), "l ", 7812738666512280684);

}

Interaction with developers:

See Bug 13.

# Bug 20:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:635:34

Bug Type: unwrap

Buf Information: iter.next() out of bound caused unwrap() None, resulting in panic.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(4268070197446523707, 4268070196469563392, false);

    let _ = unicode_segmentation::GraphemeCursor::next_boundary(&mut (_local0), "; ", 4268070197446523705);

}

Interaction with developers:

See Bug 13.

# Bug 21:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:553:22

Bug Type: utf-8

Buf Information: Program unexpected panic caused by not a char boundary when indexing `chunk` in Method GraphemeCursor::is_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(8463800222054970741, 8463951407229173877, false);

    let _ = unicode_segmentation::GraphemeCursor::is_boundary(&mut (_local0), "Ë", 8463800222054970740);

}

Interaction with developers:

See Bug 13.

# Bug 22:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:634:24

Bug Type: utf-8

Buf Information: Program unexpected panic caused by bytes index out of bound in Method GraphemeCursor::next_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(4268070197446523713, 4268070196471726080 ,false);

    let _ = unicode_segmentation::GraphemeCursor::next_boundary(&mut (_local0), "\n\n\n\n\n\n\n\n", 4268070197446522939);

}

Interaction with developers:

See Bug 13.

# Bug 23:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:716:24

Bug Type: utf-8

Buf Information: Program unexpected panic caused by not a char boundary in Method GraphemeCursor::prev_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(5208492444341520467 ,3407250190757808200 ,true);

    let _ = unicode_segmentation::GraphemeCursor::prev_boundary(&mut (_local0), "HHHZ\\HHH\0\u{e040}HHK", 5208492444341520456);

}

Interaction with developers:

See Bug 13.

# Bug 24:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:553:22

Bug Type: utf-8

Buf Information: Program unexpected panic caused by not a char boundary in Method GraphemeCursor::is_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(8102099357864587379, 8071550526791090176, false);

    let _ = unicode_segmentation::GraphemeCursor::is_boundary(&mut (_local0), "ppݶp", 8102099357864587376);

}

Interaction with developers:

See Bug 13.

# Bug 25:

Rust Crate: unicode-segmentation v1.8.0 (https://github.com/unicode-rs/unicode-segmentation)

Bug location: src/grapheme.rs:543:56

Bug Type: arith

Buf Information: Program unexpected panic caused by add overflow in Method GraphemeCursor::is_boundary.

Original Bug Report: https://github.com/unicode-rs/unicode-segmentation/issues/119

POC:

fn main() 

{

    let mut _local0 = unicode_segmentation::GraphemeCursor::new(18446744073709551615, 18446744069448138751, false);

    let _ = unicode_segmentation::GraphemeCursor::is_boundary(&mut (_local0), "\0\u{13}", 18446744073709551615);

}

Interaction with developers:

See Bug 13.