[3] ZStream: deflateEnd() called after inflateInit2() via DecompressionStream
Severity: Medium | Component: WebCore Compression Streams | 43a1b0b
Rated Medium because the observable effect is an invalid free from calling deflateEnd() on inflate-initialized zlib state, and while this produces undefined behavior that could corrupt heap metadata, the commit author was unable to reproduce a crash locally — practical exploitation depends on zlib's internal struct layout and heap state, which are not demonstrable from the diff alone.
The ZStream destructor unconditionally called deflateEnd() regardless of whether the stream was initialized for compression or decompression. The fix adds an m_operation member to track the initialization mode and branches accordingly.
Source/WebCore/Modules/compression/ZStream.cpp
+ m_operation = operation;
m_isInitialized = true;
return true;
}
ZStream::~ZStream()
{
- if (m_isInitialized)
+ if (!m_isInitialized)
+ return;
+
+ if (m_operation == Operation::Compression)
deflateEnd(&m_stream);
+ else
+ inflateEnd(&m_stream);
}
Source/WebCore/Modules/compression/ZStream.h
z_stream m_stream;
+ Operation m_operation { Operation::Compression };
bool m_isInitialized { false };
Patch Details
The patch adds an m_operation member variable of type Operation (an enum distinguishing Compression from Decompression) to the ZStream class, stored during initializeIfNecessary(). The destructor is restructured from a simple if (m_isInitialized) deflateEnd(...) to an early-return guard followed by an operation-dependent branch: deflateEnd for compression, inflateEnd for decompression. The m_operation member defaults to Operation::Compression, and m_isInitialized remains separately tracked.
Mismatched resource cleanup — destructor calls the wrong deallocation function for the resource type that was actually initialized.
Background
The Compression Streams API (CompressionStream and DecompressionStream) is a web-standard JavaScript API for streaming compression/decompression, accessible from any web page. WebKit's implementation wraps zlib via the ZStream class in Source/WebCore/Modules/compression/. zlib uses paired init/end functions: deflateInit2()/deflateEnd() for compression and inflateInit2()/inflateEnd() for decompression. These functions manage completely different internal state structures within the same z_stream object — they allocate different internal buffers, use different function pointers, and maintain different bookkeeping. Calling the wrong end function on an initialized stream is undefined behavior per the zlib API contract.
Analysis
The root cause is a classic mismatched-cleanup bug. The ZStream class was designed as a thin wrapper around zlib but failed to track which initialization path was taken, defaulting to the compression cleanup path unconditionally. When a DecompressionStream was created from JavaScript (e.g., new DecompressionStream('gzip')), it initialized the internal z_stream via inflateInit2(). On destruction — whether by garbage collection or scope exit — the destructor called deflateEnd(&m_stream), which interprets the inflate internal state as deflate internal state. This causes zlib to misinterpret internal allocations and call free() on invalid pointers derived from the wrong internal structures.
Aaa Aaaaaaa Aaaa Aaa Aaaaaa a Aaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaa Aaa Aaaaaa Aa Aaaaaaaaaa Aaaaaaaaaaaaaa Aa Aaaaaa Aa Aaaaaaa Aaaaaa Aaaaaaa Aaaa Aa Aaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaa Aaa Aaaa Aaaaaaa Aaaaaaaaa Aa Aaaaaaaa Aaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaa Aaaaaaaaaaa Aa Aaaaa Aaaaaaaaaa Aaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaaaa Aaa Aaaaaaa Aaaa Aaaa a Aaaaaa Aaaaaaaaaa Aaaaaaaaaa
Aaa Aaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaa Aaaa Aaaaaaaaa Aaaaaaaa Aaaaaa Aaaaaa Aaa Aaaa Aaaaaaaa Aaaaaaaaaaaa Aaa Aaaaaa Aaaaaa Aaaaa Aa Aaa Aaa Aaaa Aa Aaa Aaaa Aa Aaaaa Aaaaaaaaa Aaaaa Aaaaaaaa Aaaa Aa Aaaa Aaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaaa Aaa Aaaaaaaa Aaaaaaa Aaaa Aaaaaaaa Aaaaaaa Aa Aaaaaaaaa Aaaaaaaaaa Aaaaa a a Aaaaaaaa Aaaa Aaaaa Aaa Aaa Aaaaaa Aa Aaaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaaaaaaaaa Aaaa Aaaaaaaaa Aa Aaaaaaaaaaa Aaaaaaaaaa Aaaaa Aaaa Aaaaaa Aa Aaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaa Aa Aaa Aaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaa Aaaaaaa Aaa Aa Aaaaaaaaaa Aaaa Aaa Aaaaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaaaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaa Aaaaa Aaaaa Aaaaaaa Aaa Aaaa Aa Aaaaaaa Aaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaaa Aa Aaaaaaaa Aaa Aaaaaaaa Aaa Aaaaaa Aa Aaaaaa Aaaaaaaa Aaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaa Aaaa Aaaa Aaaaaaaaaaa a Aaaaaaaa Aaaaaaa Aaaaaa Aaaaa Aa Aaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaaaa
a Aaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaa Aaaaaaa Aa Aaaaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaa Aaaaaa Aaaa Aaaaaa Aaa Aaaa Aaaaaaaaaaaa Aa Aaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaaaa Aaaa Aaaaaaaaaaaa a Aaa Aaaa Aaaaaaaaaaaaa Aaaa Aa Aaaaaa Aaa Aaaa
Aaaaaaaaa Aaa Aaaaaaaa Aaaaa Aaaa Aaaaaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaaaaa Aaaaaa Aa Aaaaaaa Aaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaa Aaaa Aaaaaa Aaaaaaaaaa Aaa Aaaaaaaaa Aaaaaa Aaa Aaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaa Aa Aaaa Aaaaaaaaa Aaa Aaaaa Aa Aaa Aaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaa Aa Aaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa
🔒The heap corruption implications of this mismatched cleanup are explored, including exploitation feasibility from web content
Subscribe to read more
Audit directions
a Aaaaaaaaaa Aaaaaaaa Aaaaaaaa Aaaa Aaaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aaaaa Aaa Aaa a Aaaaaa Aaaaaaa Aaaaaaa Aaaaa Aaaaa Aaaaaaa Aaaaaaa Aaaaaaa Aaaa Aaaaaa a Aaaaaaa Aaaaaaaaa Aaaa Aaaaaa Aaaaaaaaaaaa Aaaaaaaaa Aaaaaa Aaaaaa Aaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aa Aaa Aaaaaaaa Aaaaaaa Aaaaaaaa Aaa Aaa Aaaaaaaaaaaaaa Aaaaaa
a Aaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaa Aaaaaaaaaaaaa Aaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaa Aaaaaaa Aa Aaaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaaaa Aaaa Aaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaa Aaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaa Aaaa Aaaaaaa Aaaaaaaaaaaaa Aaaaa Aaa a Aaa Aaaaaaaaa Aaa Aaaa Aaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaa a Aaaaa Aaaaaa Aaa Aaaaaaaaaaa Aaaaaaa
a Aaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaa Aaa Aaaaaaa Aaaa Aaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaa Aaaaa Aaaaaaaaaa Aaaaa Aa Aaaaaaa Aa Aaaaaa Aaaaaa Aa Aaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aaaaaaaa
🔒Multiple audit patterns identified for mismatched resource cleanup across WebKit's native library wrappers
Subscribe to read more