Skip to content

Fix out-of-bounds write with Strategy::rle and compression level 0 - #3112

Closed
PGZXB wants to merge 1 commit into
boostorg:developfrom
PGZXB:fix-issue-3109
Closed

PGZXB wants to merge 1 commit into
boostorg:developfrom
PGZXB:fix-issue-3109

Conversation

@PGZXB

@PGZXB PGZXB commented Sep 24, 2026 •

Copy link
Copy Markdown

Fixes #3109

doWrite selects the compression function from strategy_ before it
considers level_. A deflate_stream reset with level = 0 (store only)
and Strategy::rle therefore runs f_rle, which emits a stored block
without capping its size against the pending buffer. With memLevel = 1
the pending buffer is 512 bytes, so a 508-byte stored block plus its header
overruns it by one byte (ASan reports a heap-buffer-overflow WRITE of 508 in
copy_block).

As in zlib, level 0 means "store only" regardless of the strategy. Do the
same here: when level_ == 0, deflate_rle delegates to f_stored, which
enforces the pending-buffer cap, instead of entering the RLE compressor.

diff --git a/include/boost/beast/zlib/detail/deflate_stream.hpp b/include/boost/beast/zlib/detail/deflate_stream.hpp
index 6f39569..15221f9 100644
--- a/include/boost/beast/zlib/detail/deflate_stream.hpp
+++ b/include/boost/beast/zlib/detail/deflate_stream.hpp
@@ -680,6 +680,8 @@ protected:
     block_state
     deflate_rle(z_params& zs, Flush flush)
     {
+        if(level_ == 0)
+            return f_stored(zs, flush);
         return f_rle(zs, flush);
     }

Verification

Reproducer from #3109:

zlib::deflate_stream ds;
ds.reset(0, 9, 1, zlib::Strategy::rle);

std::vector<std::uint8_t> input(508, 'A');
std::vector<std::uint8_t> out(zlib::deflate_upper_bound(input.size()) + 64);

zlib::z_params zp;
zp.next_in  = input.data();
zp.avail_in = input.size();
zp.next_out = out.data();
zp.avail_out = out.size();

boost::system::error_code ec;
ds.write(zp, zlib::Flush::finish, ec);

Before: ASan reports a heap-buffer-overflow write in
deflate_stream::copy_block, reached from f_rle.

After: the reproducer runs to completion with no sanitizer report.

@PGZXB PGZXB changed the title Fix Missing pending-buffer size cap in Strategy::rle triggers out-of-bounds write in copy_bloc (#3109) Fix Missing pending-buffer size cap in Strategy::rle triggers out-of-bounds write in copy_bloc Sep 24, 2026
doWrite dispatches on strategy_ before level_, so level 0 with
Strategy::rle runs f_rle, which emits a stored block without capping its
size against the pending buffer and overruns it. Route level 0 to
f_stored, matching zlib.

Fixes boostorg#3109
@PGZXB PGZXB changed the title Fix Missing pending-buffer size cap in Strategy::rle triggers out-of-bounds write in copy_bloc Fix out-of-bounds write with Strategy::rle and compression level 0 Sep 25, 2026
@ashtum

ashtum commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

Thanks for your PR.

This issue will be addressed by #3114, along with some additional improvements.

@ashtum ashtum closed this Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing pending-buffer size cap in Strategy::rle triggers out-of-bounds write in copy_block

2 participants