Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deflate bug with windowBits == 8? #171

Closed
vinniefalco opened this issue Oct 23, 2016 · 13 comments
Closed

deflate bug with windowBits == 8? #171

vinniefalco opened this issue Oct 23, 2016 · 13 comments

Comments

@vinniefalco
Copy link

What's all this about?

    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */

https://github.com/madler/zlib/blob/master/deflate.c#L276

Does this mean that 256-byte windows are broken?

@madler
Copy link
Owner

madler commented Oct 24, 2016

Yes.

@madler madler closed this as completed Oct 24, 2016
@vinniefalco
Copy link
Author

Is this something that can be fixed? Does this mean that all existing implementations of WebSocket permessage-deflate are also broken (since they all use ZLib, and they can negotiate an 8-bit window)?

@madler
Copy link
Owner

madler commented Oct 24, 2016

Perhaps it can be fixed, but I have not tried. Nothing should be broken, since an 8-bit window zlib stream is never generated by zlib. If 8 is requested, a 9-bit window is used instead.

@vinniefalco
Copy link
Author

Here's the possible issue, a WebSocket client requests an 8-bit window. The server (using ZLib, and unaware of line 276 in deflate.c) agrees, and responds that it will use an 8-bit window.

At this point the server will compress data, and that data may contain match offsets greater than 256 (since its really using a 9 bit window). The client will receive that data and get this error:
https://github.com/madler/zlib/blob/master/inflate.c#L1130

@madler
Copy link
Owner

madler commented Oct 24, 2016

In addition to compressing with a 512-byte window, 9 bits is put in the zlib header when 8 bits is requested. So zlib, or any compliant decompressor reading that header, will use at least a 512-byte window and there will be no error on decompression.

@vinniefalco
Copy link
Author

That is certainly true if you are using a zlib header, but the WebSocket protocol specifies raw deflate streams and negotiates the window sizes separately in the HTTP request/response sequence which initiates the session:
https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#section-7.1.2

I believe all existing WebSocket implementations that use ZLib are vulnerable to this bug. Take websocketpp for example:
https://github.com/zaphoyd/websocketpp/blob/master/websocketpp/extensions/permessage_deflate/enabled.hpp#L272

If a client requests an 8-bit window size, the server will call deflateInit2 with -8 for the window size (meaning, 256 byte window and raw deflate stream). But under the hood, ZLib will really be using a 512 byte window and cause emitted deflate blocks to break the client's window invariant.

@madler
Copy link
Owner

madler commented Oct 24, 2016

You are correct. I have committed 049578f to reject requests for a window size of 256 bytes when using raw or gzip encoding.

@vinniefalco
Copy link
Author

Should this be reported in a security advisory?

@aytey
Copy link

aytey commented Oct 25, 2016

Should this be reported in a security advisory?

What's the "exploit" here? Is it simply that things "fail to work correct" if 8 (rather than 9) is passed? Or can this lead to a crash on the server-side if the wrong window is used (therefore there's a potential DoS)?

I'd also say that this wasn't a security issue for zlib, but a security issue for, e.g., websocketpp.

@vinniefalco
Copy link
Author

I don't know that it leads to a crash for a well written server, but for an application which uses raw deflate, if the application calls inflateInit with an 8 bit window size, and the other side sends deflate blocks with match offsets greater than 256, the application will get this error:
https://github.com/madler/zlib/blob/master/inflate.c#L1130

Whether or not its a denial of service depends on if the application handles errors correctly.

@aytey
Copy link

aytey commented Oct 25, 2016

Quite, so this seems like an "API usage error".

There's no security vulnerability with zlib itself, but there are potential usage scenarios when something depending on zlib could call it in an incorrect way and get "unexpected" results.

For example, for websocketpp, what does the server do if it hits that error? I assume that it checks that return code for inflate and then "does something sensible" if this isn't as expected?

Honestly, I don't really understand if there's a wider implication; my assumption is though that there's nothing serious here (e.g., like Heartbleed) -- if zlib simply processed the mis-matched window and then returned non-controlled data, then there might be an issue. As it is, zlib appears to do do some sanity checking, and returns an error on "bad" data. Nothing untoward seems like it has happening there.

Without trying it, I presume that:

https://github.com/madler/zlib/blob/master/inflate.c#L1249

gets hit and returns Z_BUF_ERROR. It is up to the caller to check the return code and handle that sensibly.

If websocketpp doesn't handle that sensibly, and does something else, then there could be a security implication there.

@vinniefalco
Copy link
Author

Your analysis is sound

pushkarnk pushed a commit to Kitura/Kitura-WebSocket-NIO that referenced this issue Jun 20, 2019
The server_max_window_bits value sent by the client in the negotiation
offer is used to configure the deflater on the server. This acceptance
is also notified to the client by returning the server_max_window_bits
header in the negotiation response.

A special case arises when we receive server_max_window_bits = 8.
There's an open zlib issue with the window size of 8. For zlib
streams, the library silently changes the window size to 9 and informs
the inflater via the zlib header. However, this apparent hack is not
feasible for raw deflate streams, which are used in WebSockets. To
take care of this fact, zlib has been patched to reject a window size
of 8, via a deflateInit2() failure.

Details here: madler/zlib#171

As a result, we need to handle a window size request of 8 as a special
case. We silently change it to 9 and inform the client via a suitable
header in the negotiation response.
pushkarnk pushed a commit to Kitura/Kitura-WebSocket-NIO that referenced this issue Jun 20, 2019
The server_max_window_bits value sent by the client in the negotiation
offer is used to configure the deflater on the server. This acceptance
is also notified to the client by returning the server_max_window_bits
header in the negotiation response.

A special case arises when we receive server_max_window_bits = 8.
There's an open zlib issue with the window size of 256 (windoBits=8).
For zlib streams, the library silently changes the windowBits to 9 and
informs the inflater via the zlib header. However, this apparent hack
is not feasible for raw deflate streams, which are used in WebSockets.
To take care of this fact, zlib has been patched to reject a window
size of 256, via a deflateInit2() failure.

Details here: madler/zlib#171

As a result, we need to handle a window size of 256 (windowBits=8) as a
special case. We silently change it to 9 and inform the client via a
suitable header in the negotiation response.
pushkarnk pushed a commit to Kitura/Kitura-WebSocket-NIO that referenced this issue Jul 4, 2019
* permessage-deflate: implement context takeover

* Use negative windowBits values for the deflater

The compression format of the output produced by zlibs deflater is decided
by the windowBits values it is configured with. We used positive windowBits
values which, according to the zlib manual, emits the zlib stream starting
with a zlib header. WebSockets use raw deflate streams, and not zlib streams.
Consequently, we had to strip the zlib header.

The deflater can be configured to emit a raw deflate format by using negative
values for the windowBits. With this in place, there's no zlib header in the
output stream.

* Handle the special case of LZ77 window size of 256

The server_max_window_bits value sent by the client in the negotiation
offer is used to configure the deflater on the server. This acceptance
is also notified to the client by returning the server_max_window_bits
header in the negotiation response.

A special case arises when we receive server_max_window_bits = 8.
There's an open zlib issue with the window size of 256 (windoBits=8).
For zlib streams, the library silently changes the windowBits to 9 and
informs the inflater via the zlib header. However, this apparent hack
is not feasible for raw deflate streams, which are used in WebSockets.
To take care of this fact, zlib has been patched to reject a window
size of 256, via a deflateInit2() failure.

Details here: madler/zlib#171

As a result, we need to handle a window size of 256 (windowBits=8) as a
special case. We silently change it to 9 and inform the client via a
suitable header in the negotiation response.

* Close deflater and inflater streams on connection close

Without context takeover, the deflater and inflater are initialized and closed
on every message. However, with context takeover, the deflater and inflater
persist for the entire lifetime of the connection. They need to be closed on a
connection close.

The deflater is on a ChannelOutboundHandler and must be closed when the
WebSocketConnections issues a channel.close(). The inflater is on a
ChannelInboundHandler, it must be closed when we receive a `closeConnection`
frame from the remote peer.
hzhuang1 pushed a commit to Linaro/warpdrive-zlib that referenced this issue Jul 31, 2019
For 64bit armv8-a there's no need to use "-mfpu=neon" to enable NEON.
But for 32bit system "-mfpu=neon" is required.

This patch adds the detection for -mfpu=neon flag.

Signed-off-by: Richael Zhuang [email protected]
@peter-gribanov
Copy link

I think it’s wrong to leave it as it is.
I understand that this breaks backward compatibility, but now it works inconsistently.
We can use a 256 byte window (in fact 512 byte) for compression, but we cannot use the same 256 byte window for decompression.

It's necessary to denide the use of a 256 byte window for both compression and decompression. This will be more correct since compression with this window is not supported.
Or, we need to change the window size from 256 bytes to 512 bytes in decompression, as in compression.

pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
pgjones added a commit to pgjones/wsproto that referenced this issue Feb 16, 2020
This is specifically to deal with the case whereby the window size is
set to 8. As zlib dropped support for 256 (8 bit) window sizes in
1.2.9, https://www.zlib.net/ChangeLog.txt, onwards. 8 bit windows were
broken before as well, madler/zlib#171. As
autobahn tests 8 bit windows the tox test would fail based on the zlib
version installed - hence the relevant autobahn tests are also
disabled.

8 bit windows are rarely used in practice, so this should be ok
practically. If not zlib needs to be fixed, see
madler/zlib#87 (comment)
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

No branches or pull requests

4 participants