From 286ea4cf103078b5b814ef91b62fb2b4e038bceb Mon Sep 17 00:00:00 2001 From: Pascal Seitz Date: Sun, 18 Oct 2020 09:52:15 +0200 Subject: [PATCH] add fuzzer, fix memcopy overlap --- fuzz/.gitignore | 4 ++++ fuzz/Cargo.toml | 26 ++++++++++++++++++++++++++ fuzz/fuzz_targets/fuzz_target_1.rs | 11 +++++++++++ src/block/decompress.rs | 12 ++++++++---- 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/fuzz_targets/fuzz_target_1.rs diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..572e03b --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..1c0038a --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,26 @@ + +[package] +name = "lz4_flex-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.3" + +[dependencies.lz4_flex] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fuzz_target_1" +path = "fuzz_targets/fuzz_target_1.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fuzz_target_1.rs b/fuzz/fuzz_targets/fuzz_target_1.rs new file mode 100644 index 0000000..5302fdb --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_target_1.rs @@ -0,0 +1,11 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use lz4_flex::block::decompress::decompress_size_prepended; +use lz4_flex::block::compress::compress_prepend_size; +fuzz_target!(|data: &[u8]| { + // fuzzed code goes here + let compressed = compress_prepend_size(data); + let decompressed = decompress_size_prepended(&compressed).unwrap(); + assert_eq!(data, decompressed); +}); diff --git a/src/block/decompress.rs b/src/block/decompress.rs index 1d7c019..adb4e2c 100644 --- a/src/block/decompress.rs +++ b/src/block/decompress.rs @@ -136,13 +136,16 @@ fn is_safe_distance(input_pos: usize, in_len: usize) -> bool { input_pos < in_len } +/// We copy 24 byte blocks, because aligned copies are faster +const BLOCK_COPY_SIZE: usize = 24; + #[inline] fn block_copy_from_src(source: *const u8, dst_ptr: *mut u8, num_items: usize) { - debug_assert!(num_items <= 24); + debug_assert!(num_items <= BLOCK_COPY_SIZE); unsafe { let dst_ptr_end = dst_ptr.add(num_items); if (dst_ptr as usize) < dst_ptr_end as usize { - std::ptr::copy_nonoverlapping(source, dst_ptr, 24); + std::ptr::copy_nonoverlapping(source, dst_ptr, BLOCK_COPY_SIZE); } } } @@ -209,8 +212,9 @@ pub fn decompress_into(input: &[u8], output: &mut Vec) -> Result<(), Error> let start_ptr = unsafe { output_ptr.sub(offset as usize) }; let match_length = (4 + (token & 0xF)) as usize; - // Write the duplicate segment to the output buffer. - if (output_ptr as usize) < unsafe { start_ptr.add(match_length) } as usize { + // Write the duplicate segment to the output buffer from the output buffer + // The blocks can overlap, make sure they are at least BLOCK_COPY_SIZE apart + if (output_ptr as usize) < unsafe { start_ptr.add(match_length).add(BLOCK_COPY_SIZE) } as usize { duplicate_overlapping(&mut output_ptr, start_ptr, match_length); } else { unsafe {