tomcat/CVE-2019-0199-3.patch

203 lines
9.2 KiB
Diff
Raw Normal View History

2020-02-28 20:54:21 -05:00
diff -Nurp apache-tomcat-9.0.10-src/java/org/apache/coyote/http2/LocalStrings.properties apache-tomcat-9.0.10-src-bak/java/org/apache/coyote/http2/LocalStrings.properties
--- apache-tomcat-9.0.10-src/java/org/apache/coyote/http2/LocalStrings.properties 2019-06-09 20:45:15.320000000 -0400
+++ apache-tomcat-9.0.10-src-bak/java/org/apache/coyote/http2/LocalStrings.properties 2019-06-09 20:46:36.793000000 -0400
@@ -98,6 +98,7 @@ stream.writeTimeout=Timeout waiting for
stream.inputBuffer.copy=Copying [{0}] bytes from inBuffer to outBuffer
stream.inputBuffer.dispatch=Data added to inBuffer when read interest is registered. Triggering a read dispatch
stream.inputBuffer.empty=The Stream input buffer is empty. Waiting for more data
+stream.inputBuffer.readTimeout=Timeout waiting to read data from client
stream.inputBuffer.reset=Stream reset
stream.inputBuffer.signal=Data added to inBuffer when read thread is waiting. Signalling that thread to continue
diff -Nurp apache-tomcat-9.0.10-src/java/org/apache/coyote/http2/Stream.java apache-tomcat-9.0.10-src-bak/java/org/apache/coyote/http2/Stream.java
--- apache-tomcat-9.0.10-src/java/org/apache/coyote/http2/Stream.java 2019-06-09 20:45:15.321000000 -0400
+++ apache-tomcat-9.0.10-src-bak/java/org/apache/coyote/http2/Stream.java 2019-06-09 20:48:21.509000000 -0400
@@ -888,10 +888,22 @@ class Stream extends AbstractStream impl
if (log.isDebugEnabled()) {
log.debug(sm.getString("stream.inputBuffer.empty"));
}
- inBuffer.wait();
+
+ inBuffer.wait(handler.getProtocol().getStreamReadTimeout());
+
if (reset) {
throw new IOException(sm.getString("stream.inputBuffer.reset"));
}
+
+ if (inBuffer.position() == 0) {
+ String msg = sm.getString("stream.inputBuffer.readTimeout");
+ StreamException se = new StreamException(
+ msg, Http2Error.ENHANCE_YOUR_CALM, getIdAsInt());
+ // Trigger a reset once control returns to Tomcat
+ coyoteResponse.setError();
+ streamOutputBuffer.reset = se;
+ throw new CloseNowException(msg, se);
+ }
} catch (InterruptedException e) {
// Possible shutdown / rst or similar. Use an
// IOException to signal to the client that further I/O
diff -Nurp apache-tomcat-9.0.10-src/test/org/apache/coyote/http2/Http2TestBase.java apache-tomcat-9.0.10-src-bak/test/org/apache/coyote/http2/Http2TestBase.java
--- apache-tomcat-9.0.10-src/test/org/apache/coyote/http2/Http2TestBase.java 2019-06-09 20:45:15.323000000 -0400
+++ apache-tomcat-9.0.10-src-bak/test/org/apache/coyote/http2/Http2TestBase.java 2019-06-09 20:53:54.809000000 -0400
@@ -28,6 +28,7 @@ import java.nio.charset.StandardCharsets
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Random;
import javax.net.SocketFactory;
@@ -300,6 +301,22 @@ public abstract class Http2TestBase exte
}
}
+ protected void sendParameterPostRequest(int streamId, byte[] padding, String body,
+ long contentLength, boolean useExpectation) throws IOException {
+ byte[] headersFrameHeader = new byte[9];
+ ByteBuffer headersPayload = ByteBuffer.allocate(128);
+ byte[] dataFrameHeader = new byte[9];
+ ByteBuffer dataPayload = ByteBuffer.allocate(128);
+
+ buildPostRequest(headersFrameHeader, headersPayload, useExpectation,
+ "application/x-www-form-urlencoded", contentLength, "/parameter", dataFrameHeader,
+ dataPayload, padding, null, null, streamId);
+ writeFrame(headersFrameHeader, headersPayload);
+ if (body != null) {
+ dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1));
+ writeFrame(dataFrameHeader, dataPayload);
+ }
+ }
protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload,
boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding,
@@ -311,14 +328,29 @@ public abstract class Http2TestBase exte
protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload,
boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding,
byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) {
+ buildPostRequest(headersFrameHeader, headersPayload, useExpectation, null, -1, "/simple",
+ dataFrameHeader, dataPayload, padding, trailersFrameHeader, trailersPayload, streamId);
+ }
+
+ protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload,
+ boolean useExpectation, String contentType, long contentLength, String path,
+ byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding,
+ byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) {
+
MimeHeaders headers = new MimeHeaders();
headers.addValue(":method").setString("POST");
headers.addValue(":scheme").setString("http");
- headers.addValue(":path").setString("/simple");
+ headers.addValue(":path").setString(path);
headers.addValue(":authority").setString("localhost:" + getPort());
if (useExpectation) {
headers.addValue("expect").setString("100-continue");
}
+ if (contentType != null) {
+ headers.addValue("content-type").setString(contentType);
+ }
+ if (contentLength > -1) {
+ headers.addValue("content-length").setLong(contentLength);
+ }
hpackEncoder.encode(headers, headersPayload);
headersPayload.flip();
@@ -507,6 +539,8 @@ public abstract class Http2TestBase exte
ctxt.addServletMappingDecoded("/large", "large");
Tomcat.addServlet(ctxt, "cookie", new CookieServlet());
ctxt.addServletMappingDecoded("/cookie", "cookie");
+ Tomcat.addServlet(ctxt, "parameter", new ParameterServlet());
+ ctxt.addServletMappingDecoded("/parameter", "parameter");
tomcat.start();
}
@@ -1205,6 +1239,24 @@ public abstract class Http2TestBase exte
}
}
+
+ static class ParameterServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ Map<String,String[]> params = req.getParameterMap();
+
+ resp.setContentType("text/plain");
+ resp.setCharacterEncoding("UTF-8");
+
+ resp.getWriter().print(params.size());
+ }
+ }
+
static class SettingValue {
private final int setting;
diff -Nurp apache-tomcat-9.0.10-src/test/org/apache/coyote/http2/TestHttp2Timeouts.java apache-tomcat-9.0.10-src-bak/test/org/apache/coyote/http2/TestHttp2Timeouts.java
--- apache-tomcat-9.0.10-src/test/org/apache/coyote/http2/TestHttp2Timeouts.java 2019-06-09 20:45:15.323000000 -0400
+++ apache-tomcat-9.0.10-src-bak/test/org/apache/coyote/http2/TestHttp2Timeouts.java 2019-06-09 20:57:22.652000000 -0400
@@ -26,7 +26,6 @@ public class TestHttp2Timeouts extends H
@Before
public void http2Connect() throws Exception {
super.http2Connect();
- sendSettings(0, false, new SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
}
@@ -36,7 +35,7 @@ public class TestHttp2Timeouts extends H
*/
@Test
public void testClientWithEmptyWindow() throws Exception {
- sendSimpleGetRequest(3);
+ sendSettings(0, false, new SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
// Settings
parser.readFrame(false);
@@ -57,6 +56,7 @@ public class TestHttp2Timeouts extends H
*/
@Test
public void testClientWithEmptyWindowLargeResponse() throws Exception {
+ sendSettings(0, false, new SettingValue(Setting.INITIAL_WINDOW_SIZE.getId(), 0));
sendLargeGetRequest(3);
// Settings
@@ -70,4 +70,36 @@ public class TestHttp2Timeouts extends H
Assert.assertEquals("3-RST-[11]\n", output.getTrace());
}
+ /*
+ * Timeout with app reading request body directly.
+ */
+ @Test
+ public void testClientPostsNoBody() throws Exception {
+ sendSimplePostRequest(3, null, false);
+
+ // Headers
+ parser.readFrame(false);
+ output.clearTrace();
+
+ parser.readFrame(false);
+
+ Assert.assertEquals("3-RST-[11]\n", output.getTrace());
+ }
+
+
+ /*
+ * Timeout with app processing parameters.
+ */
+ @Test
+ public void testClientPostsNoParameters() throws Exception {
+ sendParameterPostRequest(3, null, null, 10, false);
+
+ // Headers
+ parser.readFrame(false);
+ output.clearTrace();
+
+ parser.readFrame(false);
+
+ Assert.assertEquals("3-RST-[11]\n", output.getTrace());
+ }
}