Skip to content

Commit 936cc70

Browse files
generatedunixname26860585020226206meta-codesync[bot]
authored andcommitted
Fix OOB read in Lz4Immutable::decompress (MACA-2026-001)
Summary: `memcache/mcrouter-fbpkg` R5519-R5520 fail at the Contbuild Tracking Node: lionhead fuzz harnesses reproduce a confirmed out-of-bounds read in `Lz4Immutable::decompress` (MACA-2026-001, T267172411). A malicious memcache backend sends a Caret reply whose 16-bit match `offset` exceeds the dictionary+output window; the `size_t` subtraction underflows and `IovecCursor::peekInto` reads past the stack-local dictionary iovec. This reproduces the security-certified fix from D104024019 (abandoned only for a CodemodService landing limitation): validate `offset`, `matchPos`, and `matchLength` against the window and return `nullptr` on malformed input, like the existing literal-copy guard. Sentinel-Harness: claude Differential Revision: D112676476 fbshipit-source-id: fe74575157de68d5d9be0f1d9d7ae977c1c29af8
1 parent 6a672a9 commit 936cc70

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

mcrouter/lib/Lz4Immutable.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,16 @@ std::unique_ptr<folly::IOBuf> Lz4Immutable::decompress(
539539

540540
// Get match offset
541541
uint16_t offset = peekLE(source);
542-
size_t matchPos = dicCursor.totalLength() + (output - outputStart) - offset;
543542
source.advance(2);
543+
size_t outputProgress = static_cast<size_t>(output - outputStart);
544+
size_t window = dicCursor.totalLength() + outputProgress;
545+
if (FOLLY_UNLIKELY(offset == 0 || offset > window)) {
546+
return nullptr;
547+
}
548+
size_t matchPos = window - offset;
549+
if (FOLLY_UNLIKELY(matchPos >= dicCursor.totalLength())) {
550+
return nullptr;
551+
}
544552

545553
// Get match length
546554
size_t matchLength = token & kMlMask;
@@ -554,7 +562,9 @@ std::unique_ptr<folly::IOBuf> Lz4Immutable::decompress(
554562
matchLength += kMinMatch;
555563

556564
// Copy match
557-
if (FOLLY_UNLIKELY(output + matchLength > outputLimit)) {
565+
if (FOLLY_UNLIKELY(
566+
output + matchLength > outputLimit ||
567+
matchPos + matchLength > dicCursor.totalLength())) {
558568
return nullptr;
559569
}
560570
match.seek(matchPos);

0 commit comments

Comments
 (0)