From 43ca3df1164a022906a34d77139c515dd7273a46 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:19:26 +0100 Subject: [PATCH] Avoid an out-of-bounds panic in deflate_stored When shifting the window down, it is possible for the end of the window to be after the last initialized byte of the buffer. These uninitialized bytes don't affect the output of the compression, so we can safely skip copying them to avoid the panic. This matches the code a bit higher up which also does a window slide. --- test-libz-rs-sys/src/lib.rs | 179 ++++++++++++++++++++++++ zlib-rs/src/deflate/algorithm/stored.rs | 7 +- 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/test-libz-rs-sys/src/lib.rs b/test-libz-rs-sys/src/lib.rs index 1c869b55..ce5ccce1 100644 --- a/test-libz-rs-sys/src/lib.rs +++ b/test-libz-rs-sys/src/lib.rs @@ -1552,3 +1552,182 @@ fn inflate_strict_is_off() { (zlib_rs::ReturnCode::from(err), dest_len) }); } + +#[test] +fn deflate_stored_window_out_of_bounds() { + use core::ffi::c_int; + use zlib_rs::ReturnCode; + + let mut source = [ + 161, 161, 161, 161, 179, 179, 179, 179, 179, 179, 133, 133, 133, 133, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 95, 95, 95, 255, 179, 179, 179, 179, 179, 179, 179, + 179, 179, 43, 179, 8, 179, 133, 133, 133, 133, 13, 13, 122, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 3, 13, 13, 95, 95, 95, 13, 13, 255, 255, 255, 189, 189, 189, 189, 189, 189, 189, 0, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 173, 189, 189, 189, 189, 189, 189, 189, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 95, 95, 95, 255, 255, 255, 255, 255, 255, 255, 255, 255, 95, 95, + 95, 95, 255, 255, 189, 189, 189, 189, 189, 173, 189, 189, 189, 189, 189, 189, 189, 255, + 255, 245, 255, 255, 255, 255, 255, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 255, 255, 255, 255, 189, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 125, 125, 125, 125, 125, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 255, 18, 125, 125, + 125, 69, 125, 125, 125, 125, 255, 255, 255, 255, 125, 125, 125, 125, 125, 63, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 223, 223, 223, 223, 223, 223, 223, 223, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 255, 255, 255, + 255, 255, 255, 13, 13, 13, 13, 13, 13, 13, 95, 95, 95, 255, 179, 179, 179, 179, 179, 179, + 179, 179, 179, 43, 179, 8, 179, 133, 133, 133, 133, 13, 13, 122, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 3, 13, 13, 95, 95, 95, 13, 13, 255, 255, 255, 189, 189, 189, 189, 189, 189, + 189, 0, 189, 189, 189, 189, 189, 189, 189, 189, 189, 173, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 255, + 255, 255, 255, 189, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 125, 125, 125, 125, 125, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 255, 18, 125, 125, 125, 69, 125, 125, + 125, 125, 255, 255, 255, 255, 125, 125, 125, 125, 125, 63, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 223, 223, 223, 223, 223, 223, 223, 223, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 255, 255, 255, 255, 255, 255, 189, + 189, 189, 189, 189, 189, 183, 183, 183, 183, 183, 189, 189, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 189, 189, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 189, 189, 189, 189, 189, 66, 189, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 158, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 95, 95, 95, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 95, 95, 95, 95, 255, 255, 189, 189, 189, 189, + 189, 173, 189, 189, 189, 189, 189, 189, 189, 255, 255, 245, 255, 255, 255, 255, 255, 189, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 189, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 255, 255, 255, 189, 189, 189, 189, 189, 255, 255, 255, 255, 255, 248, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 255, 255, 255, 81, 126, 81, 81, 81, + 81, 81, 81, 81, 85, 5, 5, 5, 5, 5, 5, 5, 5, 49, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 189, + 189, 189, 189, 189, 189, 189, 255, 255, 189, 189, 189, 189, 189, 189, 19, 189, 189, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 95, 95, 95, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 95, 95, 95, 95, 255, 255, 189, 189, 189, 189, 189, 173, 189, 189, + 189, 189, 189, 189, 189, 255, 255, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 189, 189, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 189, 171, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 189, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 81, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 36, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 40, 255, 255, 255, + 255, 255, 255, 81, 81, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, + ] + .to_vec(); + + assert_eq_rs_ng!({ + let mut strm = std::mem::MaybeUninit::::zeroed(); + let err = unsafe { + deflateInit2_( + strm.as_mut_ptr(), + 0, + Z_DEFLATED, + 8, + 3, + Z_HUFFMAN_ONLY, + zlibVersion(), + std::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let buf_size = unsafe { deflateBound(strm, source.len() as u64) }; + + let mut dest = vec![0; buf_size as usize]; + let chunk = 305u32; + let flush = Z_NO_FLUSH; + + strm.next_in = source.as_mut_ptr().cast(); + strm.avail_in = chunk; // First chunk. + strm.next_out = dest.as_mut_ptr().cast(); + strm.avail_out = dest.len().try_into().unwrap(); + + // Deflate first chunk. + let err = unsafe { deflate(strm, flush) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + // Change the parameters. + let new_level = 0; + let new_strategy = Z_DEFAULT_STRATEGY; + let err = unsafe { deflateParams(strm, new_level, new_strategy) }; + match ReturnCode::from(err) { + ReturnCode::Ok => {} + ReturnCode::BufError => { + // Flushing the current pending data may run us out of buffer space. + // Worst case double the buffer size. + let add_space = Ord::min(chunk, buf_size as u32); + dest.resize(dest.len() + add_space as usize, 0); + + // If extend() reallocates, it may have moved in memory. + strm.next_out = dest.as_mut_ptr(); + strm.avail_out += add_space; + + let err = unsafe { deflateParams(strm, new_level, new_strategy) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + err => panic!("fatal {:?}", err), + } + + // Deflate the rest in chunks. + let mut left: u32 = source.len() as u32 - chunk; + while left > 0 { + // Write the chunk. + let avail = Ord::min(chunk, left).try_into().unwrap(); + strm.avail_in = avail; + let err = unsafe { deflate(strm, flush) }; + match ReturnCode::from(err) { + ReturnCode::Ok => { + left -= avail; + } + ReturnCode::BufError => { + // Worst case double the buffer size. + let add_space = Ord::min(chunk, buf_size as u32); + dest.resize(dest.len() + add_space as usize, 0); + + // If extend() reallocates, it may have moved in memory. + strm.next_out = dest.as_mut_ptr(); + strm.avail_out += add_space; + + left -= avail - strm.avail_in; + } + err => panic!("fatal {:?}", err), + } + } + + assert_eq!(left, 0); + + let _ = unsafe { deflateEnd(strm) }; + }); +} diff --git a/zlib-rs/src/deflate/algorithm/stored.rs b/zlib-rs/src/deflate/algorithm/stored.rs index 17d042c9..6c18db36 100644 --- a/zlib-rs/src/deflate/algorithm/stored.rs +++ b/zlib-rs/src/deflate/algorithm/stored.rs @@ -181,10 +181,15 @@ pub fn deflate_stored(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockS let state = &mut stream.state; state.block_start -= state.w_size as isize; state.strstart -= state.w_size; + + // make sure we don't copy uninitialized bytes. While we discard the first lower w_size + // bytes, it is not guaranteed that the upper w_size bytes are all initialized + let copy = Ord::min(state.strstart, state.window.filled().len() - state.w_size); + state .window .filled_mut() - .copy_within(state.w_size..state.w_size + state.strstart, 0); + .copy_within(state.w_size..state.w_size + copy, 0); if state.matches < 2 { // add a pending slide_hash