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

max_window_bits is inclusive of 8 for WebSocket permessage-deflate compression #8702

Open
riyafa opened this issue Jan 4, 2019 · 4 comments

Comments

@riyafa
Copy link
Contributor

riyafa commented Jan 4, 2019

Expected behavior

It should be possible to have the window size for permessage-deflate compression as 8 according to the spec: https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-13#section-8.1.2

Actual behavior

Though it is allowed the encoding of a WebSocket frame when the window size is 8 fails:

io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: windowBits: 8 (expected: 9-15)
	at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:107)
	at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)
	at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801)
	at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814)
	at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794)
	at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:837)
	at websocket.WebSocketClientHandler.channelRead0(WebSocketClientHandler.java:108)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:656)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:591)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:508)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:470)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalArgumentException: windowBits: 8 (expected: 9-15)
	at io.netty.handler.codec.compression.JZlibEncoder.<init>(JZlibEncoder.java:126)
	at io.netty.handler.codec.compression.ZlibCodecFactory.newZlibEncoder(ZlibCodecFactory.java:81)
	at io.netty.handler.codec.http.websocketx.extensions.compression.DeflateEncoder.encode(DeflateEncoder.java:74)
	at io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateEncoder.encode(PerMessageDeflateEncoder.java:66)
	at io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateEncoder.encode(PerMessageDeflateEncoder.java:30)
	at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:89)
	... 38 more

Steps to reproduce

Create a client implementation as in the following project:
https://github.com/riyafa/netty-websocket-compression.git

Note that I am using a custom WebSocketClientCompressionHandler

Use the autobahn testsuite and run the server. Use the following content in the fuzzingserver.json file:

{
   "url": "ws://127.0.0.1:9001",
   "outdir": "./reports/clients",
   "cases": ["13.5.1"],
   "exclude-cases": [],
   "exclude-agent-cases": {}
}

Simply run the main method of the WebSocketClient after starting the autobahn server.
If using any other server the response from server should be something similar to the following:

HTTP/1.1 101 Switching Protocols
Server: AutobahnTestSuite/0.8.0-0.10.9
X-Powered-By: AutobahnPython/0.10.9
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: R7uAXLScZyB71yTc1JmRuFVSIo8=
Sec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover; client_max_window_bits=8
content-length: 0

with client_max_window_bits=8

Minimal yet complete reproducer code (or URL to code)

https://github.com/riyafa/netty-websocket-compression.git

Netty version

4.1.32.Final

JVM version (e.g. java -version)

1.8.0_191

OS version (e.g. uname -a)

Ubuntu 18.10

@riyafa
Copy link
Contributor Author

riyafa commented Jan 4, 2019

This is because of the following check in JZlibEncoder:

if (windowBits < 9 || windowBits > 15) {
throw new IllegalArgumentException(
"windowBits: " + windowBits + " (expected: 9-15)");
}

That because of a similar check in jzlib:
https://github.com/ymnk/jzlib/blob/a21be20213d66eff15904d925e9b721956a01ef7/src/main/java/com/jcraft/jzlib/Deflater.java#L109-L111

But the window size from the range 8..15 is supported in zlib:
http://www.zlib.net/manual.html#Advanced

I created an issue in jzlib on this even though the project does not seem to be maintained:
ymnk/jzlib#23

@amizurov
Copy link
Contributor

Interesting thoughts about this situation: https://github.com/faye/permessage-deflate-node/wiki/Denial-of-service-caused-by-invalid-windowBits-parameter-passed-to-zlib.createDeflateRaw()
For examples on Jetty server this is is not supported:

               case "client_max_window_bits":
               case "server_max_window_bits":
               {
                   // Not supported by Jetty
                   // Don't negotiate these parameters
                   break;
               }

@uzador
Copy link

uzador commented Aug 29, 2022

Hi @riyafa @amizurov I've faced the similar issue and I'm curious if you found any solution for that could you advise what you did?

@amizurov
Copy link
Contributor

amizurov commented Sep 5, 2022

@uzador Hello, I didn't look deeply what can be done on the Netty side.

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

3 participants