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:
112
112
${PREPARE_SHELL}
113
113
.evergreen/check-clippy.sh
114
114
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
+
115
126
" check rustdoc " :
116
127
- command : shell.exec
117
128
type : test
@@ -162,6 +173,10 @@ tasks:
162
173
commands :
163
174
- func : " check rustdoc"
164
175
176
+ - name : " run-fuzzer"
177
+ commands :
178
+ - func : " run fuzzer"
179
+
165
180
axes :
166
181
- id : " extra-rust-versions"
167
182
values :
@@ -200,3 +215,11 @@ buildvariants:
200
215
- name : " check-clippy"
201
216
- name : " check-rustfmt"
202
217
- 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
11
11
[dependencies .bson ]
12
12
path = " .."
13
13
[dependencies .libfuzzer-sys ]
14
- git = " https://github.com/rust-fuzz/libfuzzer-sys.git "
14
+ version = " 0.4.0 "
15
15
16
16
# Prevent this from interfering with workspaces
17
17
[workspace ]
18
18
members = [" ." ]
19
19
20
- [[bin ]]
21
- name = " fuzz_target_1"
22
- path = " fuzz_targets/fuzz_target_1.rs"
23
-
24
20
[[bin ]]
25
21
name = " deserialize"
26
22
path = " 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> {
171
171
where
172
172
F : FnOnce ( DocumentAccess < ' _ , ' de > ) -> Result < O > ,
173
173
{
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" ) ) ?;
175
177
let out = f ( DocumentAccess {
176
178
root_deserializer : self ,
177
179
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> {
175
175
ElementType :: Binary => {
176
176
let len = i32_from_slice ( & self . doc . as_bytes ( ) [ valueoffset..] ) ? as usize ;
177
177
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 ) ?;
179
186
let subtype = BinarySubtype :: from ( self . doc . as_bytes ( ) [ valueoffset + 4 ] ) ;
180
187
let data = match subtype {
181
188
BinarySubtype :: BinaryOld => {
Original file line number Diff line number Diff line change @@ -171,7 +171,7 @@ fn f64_from_slice(val: &[u8]) -> Result<f64> {
171
171
/// Given a u8 slice, return an i32 calculated from the first four bytes in
172
172
/// little endian order.
173
173
fn i32_from_slice ( val : & [ u8 ] ) -> Result < i32 > {
174
- let arr = val
174
+ let arr: [ u8 ; 4 ] = val
175
175
. get ( 0 ..4 )
176
176
. and_then ( |s| s. try_into ( ) . ok ( ) )
177
177
. ok_or_else ( || {
@@ -213,6 +213,15 @@ fn read_nullterminated(buf: &[u8]) -> Result<&str> {
213
213
}
214
214
215
215
fn 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
+
216
225
let length = i32_from_slice ( & buf[ ..4 ] ) ?;
217
226
let end = checked_add ( usize_try_from_i32 ( length) ?, 4 ) ?;
218
227
You can’t perform that action at this time.
0 commit comments