Skip to content

Commit 5584765

Browse files
baranowbropalka
authored andcommitted
[UNDERTOW-2781] Limit chunk size so it does not overlap state
1 parent 4223cdf commit 5584765

2 files changed

Lines changed: 112 additions & 3 deletions

File tree

core/src/main/java/io/undertow/conduits/ChunkReader.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,8 @@ class ChunkReader {
4343
private static final long FLAG_READING_TILL_END_OF_LINE = 1L << 60L;
4444
private static final long FLAG_READING_NEWLINE = 1L << 59L;
4545
private static final long FLAG_READING_AFTER_LAST = 1L << 58L;
46-
4746
private static final long MASK_COUNT = longBitMask(0, 56);
48-
49-
private static final long LIMIT = Long.MAX_VALUE >> 4;
47+
private static final long LIMIT = Long.MAX_VALUE >> 6;
5048

5149
private long state;
5250
private final BytesCounter<? extends IOException> maxEntitySizeChecker;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2026 Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package io.undertow.conduits;
20+
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.io.OutputStream;
24+
import java.net.Socket;
25+
import java.net.SocketException;
26+
27+
import org.junit.After;
28+
import org.junit.Assert;
29+
import org.junit.Before;
30+
import org.junit.BeforeClass;
31+
import org.junit.Test;
32+
import org.junit.runner.RunWith;
33+
import org.xnio.IoUtils;
34+
35+
import io.undertow.server.handlers.ResponseCodeHandler;
36+
import io.undertow.testutils.DefaultServer;
37+
import io.undertow.testutils.HttpOneOnly;
38+
import io.undertow.testutils.ProxyIgnore;
39+
40+
/**
41+
* Test if there is no overflow of state in chunk handling.
42+
*
43+
* @author baranowb
44+
*/
45+
@RunWith(DefaultServer.class)
46+
@ProxyIgnore
47+
@HttpOneOnly
48+
public class ChunkSizeTestCase {
49+
@BeforeClass
50+
public static void setup() {
51+
DefaultServer.setRootHandler(ResponseCodeHandler.HANDLE_200);
52+
}
53+
54+
private Socket client;
55+
private OutputStream clientOutputStream;
56+
private InputStream clientInputStream;
57+
58+
@Before
59+
public void before() throws Exception {
60+
client = new Socket();
61+
client.connect(DefaultServer.getDefaultServerAddress());
62+
clientOutputStream = client.getOutputStream();
63+
clientInputStream = client.getInputStream();
64+
}
65+
66+
@After
67+
public void after() throws Exception {
68+
IoUtils.safeClose(client);
69+
}
70+
71+
@Test
72+
public void testForgedSmuggling() throws IOException, InterruptedException {
73+
74+
final String msg = "POST /hello-servlet/greeting HTTP/1.1\r\n"
75+
+ "Host: localhost\r\n"
76+
+ "Content-Type: appication/x-www-form-urlencoded\r\n"
77+
+ "Transfer-Encoding: chunked\r\n"
78+
+ "Connection: keep-alive\r\n"
79+
+ "\r\n"
80+
+ "4000000000000000\r\n";
81+
82+
clientOutputStream.write(msg.getBytes());
83+
clientOutputStream.flush();
84+
Thread.currentThread().sleep(300);
85+
final String msg2 = "\r\nGET /smuggled HTTP/1.1\r\n"
86+
+ "Host: 127.0.0.1:8080\r\n"
87+
+ "Connection: close"
88+
+ "\r\n\r\n";
89+
clientOutputStream.write(msg2.getBytes());
90+
clientOutputStream.flush();
91+
Thread.currentThread().sleep(3000);
92+
byte[] x = readAvailable();
93+
//if we fail, we will get two responses - 200 and 400 in this setup.
94+
Assert.assertEquals(new String(x), 0, x.length);
95+
96+
}
97+
98+
public byte[] readAvailable() throws IOException {
99+
byte[] buf = new byte[4096];
100+
try {
101+
int read = clientInputStream.read(buf);
102+
if (read <= 0) return new byte[0];
103+
byte[] result = new byte[read];
104+
System.arraycopy(buf, 0, result, 0, read);
105+
return result;
106+
} catch (SocketException expected) {
107+
return new byte[0];
108+
}
109+
}
110+
111+
}

0 commit comments

Comments
 (0)