Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .evergreen/run-fuzzer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ run_fuzzer() {
}

# Run existing targets
run_fuzzer "deserialize"
run_fuzzer "decode"
run_fuzzer "raw_deserialize"
run_fuzzer "raw_deserialize_utf8_lossy"
run_fuzzer "iterate"

# Run new security-focused targets
run_fuzzer "type_markers"
run_fuzzer "string_handling"
run_fuzzer "serialization"
run_fuzzer "encoding"
4 changes: 3 additions & 1 deletion .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ set -o errexit

. ~/.cargo/env

RUST_BACKTRACE=1 cargo test
# Test with default features and excluding doctests (some of which require the 'serde' feature)
RUST_BACKTRACE=1 cargo test --all-targets
# Test with all features and including doctests
RUST_BACKTRACE=1 cargo test --all-features

cd serde-tests
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ serde_path_to_error = ["dep:serde_path_to_error"]
# if enabled, include serde_with interop.
# should be used in conjunction with chrono-0_4 or uuid-0_8.
serde_with-3 = ["dep:serde_with"]
serde = ["dep:serde"]

[lib]
name = "bson"
Expand All @@ -55,7 +56,7 @@ name = "bson"
ahash = "0.8.0"
chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
rand = "0.9"
serde = { version = "1.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", features = ["preserve_order"] }
indexmap = "2.1.0"
hex = "0.4.2"
Expand Down
11 changes: 0 additions & 11 deletions examples/deserialize.rs

This file was deleted.

26 changes: 0 additions & 26 deletions examples/serialize.rs

This file was deleted.

Binary file removed examples/test.bson
Binary file not shown.
1 change: 1 addition & 0 deletions fuzz/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
target
corpus
artifacts
Cargo.lock
9 changes: 5 additions & 4 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ cargo-fuzz = true

[dependencies.bson]
path = ".."
features = ["serde"]

[dependencies.libfuzzer-sys]
version = "0.4.0"
Expand All @@ -24,8 +25,8 @@ version = "1.0"
members = ["."]

[[bin]]
name = "deserialize"
path = "fuzz_targets/deserialize.rs"
name = "decode"
path = "fuzz_targets/decode.rs"

[[bin]]
name = "iterate"
Expand All @@ -48,8 +49,8 @@ name = "string_handling"
path = "fuzz_targets/string_handling.rs"

[[bin]]
name = "serialization"
path = "fuzz_targets/serialization.rs"
name = "encoding"
path = "fuzz_targets/encoding.rs"

[[bin]]
name = "generate_corpus"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use bson::Document;
use std::io::Cursor;

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = Document::from_reader(&mut Cursor::new(&buf[..])) {
if let Ok(doc) = Document::decode_from_reader(&mut Cursor::new(&buf[..])) {
let mut vec = Vec::with_capacity(buf.len());
let _ = doc.to_writer(&mut vec);
let _ = doc.encode_to_writer(&mut vec);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,19 @@ fn compare_values(val1: &Bson, val2: &Bson) -> bool {
}

fuzz_target!(|input: &[u8]| {
if let Ok(rawdoc) = RawDocument::from_bytes(&input) {
if let Ok(rawdoc) = RawDocument::decode_from_bytes(&input) {
if let Ok(doc) = Document::try_from(rawdoc) {
let out = RawDocumentBuf::try_from(&doc).unwrap();
let out_bytes = out.as_bytes();
if input != out_bytes {
let reserialized = RawDocument::from_bytes(&out_bytes).unwrap();
let reserialized_doc = Document::try_from(reserialized).unwrap();
// Ensure that the reserialized document is the same as the original document, the
let reencoded = RawDocument::decode_from_bytes(&out_bytes).unwrap();
let reencoded_doc = Document::try_from(reencoded).unwrap();
// Ensure that the re-encoded document is the same as the original document, the
// bytes can differ while still resulting in the same Document.
if !compare_docs(&doc, &reserialized_doc) {
if !compare_docs(&doc, &reencoded_doc) {
panic!(
"Reserialized document is not the same as the original document: {:?} != \
{:?}",
doc, reserialized_doc
"Reencoded document is not the same as the original document: {:?} != {:?}",
doc, reencoded_doc
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/iterate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extern crate bson;
use bson::RawDocument;

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = RawDocument::from_bytes(buf) {
if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
for _ in doc {}
}
});
5 changes: 2 additions & 3 deletions fuzz/fuzz_targets/raw_deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ extern crate bson;
use bson::Document;

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = bson::from_slice::<Document>(buf) {
let mut vec = Vec::with_capacity(buf.len());
let _ = doc.to_writer(&mut vec);
if let Ok(doc) = bson::deserialize_from_slice::<Document>(buf) {
let _ = bson::serialize_to_vec(&doc);
}
});
10 changes: 5 additions & 5 deletions fuzz/fuzz_targets/raw_deserialize_utf8_lossy.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![no_main]
#[macro_use] extern crate libfuzzer_sys;
#[macro_use]
extern crate libfuzzer_sys;
extern crate bson;
use bson::Document;
use bson::{serde_helpers::Utf8LossyDeserialization, Document};

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = bson::from_slice_utf8_lossy::<Document>(buf) {
let mut vec = Vec::with_capacity(buf.len());
let _ = doc.to_writer(&mut vec);
if let Ok(doc) = bson::deserialize_from_slice::<Utf8LossyDeserialization<Document>>(buf) {
let _ = bson::serialize_to_vec(&doc.0);
}
});
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/string_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
use std::convert::TryInto;

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = RawDocument::from_bytes(buf) {
if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
for elem in doc.iter_elements().flatten() {
// Convert to RawBsonRef and check string-related types
if let Ok(bson) = elem.try_into() {
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/type_markers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bson::{RawBsonRef, RawDocument};
use std::convert::TryInto;

fuzz_target!(|buf: &[u8]| {
if let Ok(doc) = RawDocument::from_bytes(buf) {
if let Ok(doc) = RawDocument::decode_from_bytes(buf) {
for elem in doc.iter_elements().flatten() {
let _: Result<RawBsonRef, _> = elem.try_into();
}
Expand Down
24 changes: 18 additions & 6 deletions fuzz/generate_corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ fn generate_length_edge_cases(dir: &Path) -> std::io::Result<()> {
let min_doc = doc! {};
fs::write(
target_dir.join("min_doc"),
bson::to_vec(&min_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
min_doc
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

// Document with length near i32::MAX
let large_doc = doc! { "a": "b".repeat(i32::MAX as usize / 2) };
fs::write(
target_dir.join("large_doc"),
bson::to_vec(&large_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
large_doc
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

Ok(())
Expand Down Expand Up @@ -73,7 +77,9 @@ fn generate_type_marker_cases(dir: &Path) -> std::io::Result<()> {
};
fs::write(
target_dir.join("all_types"),
bson::to_vec(&all_types).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
all_types
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

Ok(())
Expand All @@ -100,7 +106,9 @@ fn generate_string_edge_cases(dir: &Path) -> std::io::Result<()> {
};
fs::write(
target_dir.join("utf8_cases"),
bson::to_vec(&utf8_cases).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
utf8_cases
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

Ok(())
Expand All @@ -124,7 +132,9 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
}
fs::write(
target_dir.join("nested_doc"),
bson::to_vec(&nested_doc).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
nested_doc
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

// Document with large binary data
Expand All @@ -136,7 +146,9 @@ fn generate_serialization_cases(dir: &Path) -> std::io::Result<()> {
};
fs::write(
target_dir.join("large_binary"),
bson::to_vec(&large_binary).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
large_binary
.encode_to_vec()
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?,
)?;

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion serde-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"
default = []

[dependencies]
bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde_with-3"] }
bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3"] }
serde = { version = "1.0", features = ["derive"] }
pretty_assertions = "0.6.1"
hex = "0.4.2"
Expand Down
16 changes: 8 additions & 8 deletions serde-tests/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,18 @@ fn owned_raw_bson() {
});

let mut doc_buf = RawDocumentBuf::new();
doc_buf.append("a", "key");
doc_buf.append("number", 12);
doc_buf.append("bool", false);
doc_buf.append("nu", RawBson::Null);
doc_buf.append("a", "key").unwrap();
doc_buf.append("number", 12).unwrap();
doc_buf.append("bool", false).unwrap();
doc_buf.append("nu", RawBson::Null).unwrap();

let mut array_buf = RawArrayBuf::new();
array_buf.push(1);
array_buf.push("string");
array_buf.push(1).unwrap();
array_buf.push("string").unwrap();

let mut bson_doc = RawDocumentBuf::new();
bson_doc.append("first", true);
bson_doc.append("second", "string");
bson_doc.append("first", true).unwrap();
bson_doc.append("second", "string").unwrap();

let expected = Foo {
doc_buf,
Expand Down
Loading