File tree Expand file tree Collapse file tree 9 files changed +90
-8
lines changed Expand file tree Collapse file tree 9 files changed +90
-8
lines changed Original file line number Diff line number Diff line change @@ -112,6 +112,17 @@ functions:
112112 ${PREPARE_SHELL}
113113 .evergreen/check-clippy.sh
114114
115+ " run fuzzer " :
116+ - command : shell.exec
117+ type : test
118+ params :
119+ shell : bash
120+ working_dir : " src"
121+ script : |
122+ ${PREPARE_SHELL}
123+ .evergreen/install-fuzzer.sh
124+ .evergreen/run-fuzzer.sh
125+
115126 " check rustdoc " :
116127 - command : shell.exec
117128 type : test
@@ -162,6 +173,10 @@ tasks:
162173 commands :
163174 - func : " check rustdoc"
164175
176+ - name : " run-fuzzer"
177+ commands :
178+ - func : " run fuzzer"
179+
165180axes :
166181 - id : " extra-rust-versions"
167182 values :
@@ -200,3 +215,11 @@ buildvariants:
200215 - name : " check-clippy"
201216 - name : " check-rustfmt"
202217 - name : " check-rustdoc"
218+
219+ -
220+ name : " fuzz"
221+ display_name : " Raw BSON Fuzzer"
222+ run_on :
223+ - ubuntu1804-test
224+ tasks :
225+ - name : " run-fuzzer"
Original file line number Diff line number Diff line change 1+ #! /bin/sh
2+
3+ set -o errexit
4+
5+ . ~ /.cargo/env
6+
7+ cargo install cargo-fuzz
Original file line number Diff line number Diff line change 1+ #! /bin/sh
2+
3+ set -o errexit
4+
5+ . ~ /.cargo/env
6+
7+ cd fuzz
8+
9+ # each runs for a minute
10+ cargo +nightly fuzz run deserialize -- -rss_limit_mb=4096 -max_total_time=60
11+ cargo +nightly fuzz run raw_deserialize -- -rss_limit_mb=4096 -max_total_time=60
12+ cargo +nightly fuzz run iterate -- -rss_limit_mb=4096 -max_total_time=60
Original file line number Diff line number Diff line change @@ -11,16 +11,20 @@ cargo-fuzz = true
1111[dependencies .bson ]
1212path = " .."
1313[dependencies .libfuzzer-sys ]
14- git = " https://github.com/rust-fuzz/libfuzzer-sys.git "
14+ version = " 0.4.0 "
1515
1616# Prevent this from interfering with workspaces
1717[workspace ]
1818members = [" ." ]
1919
20- [[bin ]]
21- name = " fuzz_target_1"
22- path = " fuzz_targets/fuzz_target_1.rs"
23-
2420[[bin ]]
2521name = " deserialize"
2622path = " fuzz_targets/deserialize.rs"
23+
24+ [[bin ]]
25+ name = " iterate"
26+ path = " fuzz_targets/iterate.rs"
27+
28+ [[bin ]]
29+ name = " raw_deserialize"
30+ path = " fuzz_targets/raw_deserialize.rs"
Original file line number Diff line number Diff line change 1+ #![ no_main]
2+ #[ macro_use] extern crate libfuzzer_sys;
3+ extern crate bson;
4+ use bson:: RawDocument ;
5+
6+ fuzz_target ! ( |buf: & [ u8 ] | {
7+ if let Ok ( doc) = RawDocument :: from_bytes( buf) {
8+ for _ in doc { }
9+ }
10+ } ) ;
Original file line number Diff line number Diff line change 1+ #![ no_main]
2+ #[ macro_use] extern crate libfuzzer_sys;
3+ extern crate bson;
4+ use bson:: Document ;
5+
6+ fuzz_target ! ( |buf: & [ u8 ] | {
7+ let _ = bson:: from_slice:: <Document >( buf) ;
8+ } ) ;
Original file line number Diff line number Diff line change @@ -171,7 +171,9 @@ impl<'de> Deserializer<'de> {
171171 where
172172 F : FnOnce ( DocumentAccess < ' _ , ' de > ) -> Result < O > ,
173173 {
174- let mut length_remaining = read_i32 ( & mut self . bytes ) ? - 4 ;
174+ let mut length_remaining = read_i32 ( & mut self . bytes ) ?
175+ . checked_sub ( 4 )
176+ . ok_or_else ( || Error :: custom ( "invalid length, less than min document size" ) ) ?;
175177 let out = f ( DocumentAccess {
176178 root_deserializer : self ,
177179 length_remaining : & mut length_remaining,
Original file line number Diff line number Diff line change @@ -175,7 +175,14 @@ impl<'a> Iterator for Iter<'a> {
175175 ElementType :: Binary => {
176176 let len = i32_from_slice ( & self . doc . as_bytes ( ) [ valueoffset..] ) ? as usize ;
177177 let data_start = valueoffset + 4 + 1 ;
178- self . verify_enough_bytes ( valueoffset, len) ?;
178+
179+ if len >= i32:: MAX as usize {
180+ return Err ( Error :: new_without_key ( ErrorKind :: MalformedValue {
181+ message : format ! ( "binary length exceeds maximum: {}" , len) ,
182+ } ) ) ;
183+ }
184+
185+ self . verify_enough_bytes ( valueoffset + 4 , len + 1 ) ?;
179186 let subtype = BinarySubtype :: from ( self . doc . as_bytes ( ) [ valueoffset + 4 ] ) ;
180187 let data = match subtype {
181188 BinarySubtype :: BinaryOld => {
Original file line number Diff line number Diff line change @@ -171,7 +171,7 @@ fn f64_from_slice(val: &[u8]) -> Result<f64> {
171171/// Given a u8 slice, return an i32 calculated from the first four bytes in
172172/// little endian order.
173173fn i32_from_slice ( val : & [ u8 ] ) -> Result < i32 > {
174- let arr = val
174+ let arr: [ u8 ; 4 ] = val
175175 . get ( 0 ..4 )
176176 . and_then ( |s| s. try_into ( ) . ok ( ) )
177177 . ok_or_else ( || {
@@ -213,6 +213,15 @@ fn read_nullterminated(buf: &[u8]) -> Result<&str> {
213213}
214214
215215fn read_lenencoded ( buf : & [ u8 ] ) -> Result < & str > {
216+ if buf. len ( ) < 4 {
217+ return Err ( Error :: new_without_key ( ErrorKind :: MalformedValue {
218+ message : format ! (
219+ "expected buffer with string to contain at least 4 bytes, but it only has {}" ,
220+ buf. len( )
221+ ) ,
222+ } ) ) ;
223+ }
224+
216225 let length = i32_from_slice ( & buf[ ..4 ] ) ?;
217226 let end = checked_add ( usize_try_from_i32 ( length) ?, 4 ) ?;
218227
You can’t perform that action at this time.
0 commit comments