[tomcat8] 01/05: Fix CVE-2017-5647, CVE-2017-5648, CVE-2017-5650, CVE-2017-5651
Markus Koschany
apo at moszumanska.debian.org
Wed Apr 12 12:11:01 UTC 2017
This is an automated email from the git hooks/post-receive script.
apo pushed a commit to branch master
in repository tomcat8.
commit 38af11ab73a485325ddb5c969586e59f6bb367f4
Author: Markus Koschany <apo at debian.org>
Date: Wed Apr 12 00:13:43 2017 +0200
Fix CVE-2017-5647, CVE-2017-5648, CVE-2017-5650, CVE-2017-5651
Thanks: Salvatore Bonaccorso for the report.
Closes: #860068
Add CVE patches to series file.
---
debian/patches/CVE-2017-5647.patch | 255 +++++++++++++++++++++++++++++++++++++
debian/patches/CVE-2017-5648.patch | 64 ++++++++++
debian/patches/CVE-2017-5650.patch | 25 ++++
debian/patches/CVE-2017-5651.patch | 156 +++++++++++++++++++++++
debian/patches/series | 4 +
5 files changed, 504 insertions(+)
diff --git a/debian/patches/CVE-2017-5647.patch b/debian/patches/CVE-2017-5647.patch
new file mode 100644
index 0000000..832372d
--- /dev/null
+++ b/debian/patches/CVE-2017-5647.patch
@@ -0,0 +1,255 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 11 Apr 2017 22:18:52 +0200
+Subject: CVE-2017-5647
+
+Origin: http://svn.apache.org/r1788932
+---
+ java/org/apache/coyote/AbstractProtocol.java | 7 ++--
+ java/org/apache/coyote/http11/Http11Processor.java | 12 ++++++-
+ java/org/apache/tomcat/util/net/AprEndpoint.java | 35 +++++++++++++------
+ java/org/apache/tomcat/util/net/Nio2Endpoint.java | 25 +++++++++-----
+ java/org/apache/tomcat/util/net/NioEndpoint.java | 26 +++++++++++----
+ .../apache/tomcat/util/net/SendfileDataBase.java | 6 ++--
+ .../tomcat/util/net/SendfileKeepAliveState.java | 39 ++++++++++++++++++++++
+ 7 files changed, 116 insertions(+), 34 deletions(-)
+ create mode 100644 java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
+
+diff --git a/java/org/apache/coyote/AbstractProtocol.java b/java/org/apache/coyote/AbstractProtocol.java
+index e69e984..3aa5dec 100644
+--- a/java/org/apache/coyote/AbstractProtocol.java
++++ b/java/org/apache/coyote/AbstractProtocol.java
+@@ -870,10 +870,9 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler,
+ wrapper.registerReadInterest();
+ } else if (state == SocketState.SENDFILE) {
+ // Sendfile in progress. If it fails, the socket will be
+- // closed. If it works, the socket will be re-added to the
+- // poller
+- connections.remove(socket);
+- release(processor);
++ // closed. If it works, the socket either be added to the
++ // poller (or equivalent) to await more data or processed
++ // if there are any pipe-lined requests remaining.
+ } else if (state == SocketState.UPGRADED) {
+ // Don't add sockets back to the poller if this was a
+ // non-blocking write otherwise the poller may trigger
+diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
+index 5a1c766..e260a39 100644
+--- a/java/org/apache/coyote/http11/Http11Processor.java
++++ b/java/org/apache/coyote/http11/Http11Processor.java
+@@ -58,6 +58,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint;
+ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+ import org.apache.tomcat.util.net.SSLSupport;
+ import org.apache.tomcat.util.net.SendfileDataBase;
++import org.apache.tomcat.util.net.SendfileKeepAliveState;
+ import org.apache.tomcat.util.net.SocketWrapperBase;
+ import org.apache.tomcat.util.res.StringManager;
+
+@@ -1601,7 +1602,16 @@ public class Http11Processor extends AbstractProcessor {
+ openSocket = keepAlive;
+ // Do sendfile as needed: add socket to sendfile and end
+ if (sendfileData != null && !getErrorState().isError()) {
+- sendfileData.keepAlive = keepAlive;
++ if (keepAlive) {
++ if (available(false) == 0) {
++ sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
++ } else {
++ sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
++ }
++ } else {
++ sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
++ }
++
+ switch (socketWrapper.processSendfile(sendfileData)) {
+ case DONE:
+ // If sendfile is complete, no need to break keep-alive loop
+diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
+index 09d4af3..8860777 100644
+--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
++++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
+@@ -2134,20 +2134,33 @@ public class AprEndpoint extends AbstractEndpoint<Long> implements SNICallBack {
+ state.length -= nw;
+ if (state.length == 0) {
+ remove(state);
+- if (state.keepAlive) {
++ switch (state.keepAliveState) {
++ case NONE: {
++ // Close the socket since this is
++ // the end of the not keep-alive request.
++ closeSocket(state.socket);
++ break;
++ }
++ case PIPELINED: {
+ // Destroy file descriptor pool, which should close the file
+ Pool.destroy(state.fdpool);
+- Socket.timeoutSet(state.socket,
+- getSoTimeout() * 1000);
+- // If all done put the socket back in the
+- // poller for processing of further requests
+- getPoller().add(
+- state.socket, getKeepAliveTimeout(),
++ Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
++ // Process the pipelined request data
++ if (!processSocket(state.socket, SocketEvent.OPEN_READ)) {
++ closeSocket(state.socket);
++ }
++ break;
++ }
++ case OPEN: {
++ // Destroy file descriptor pool, which should close the file
++ Pool.destroy(state.fdpool);
++ Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
++ // Put the socket back in the poller for
++ // processing of further requests
++ getPoller().add(state.socket, getKeepAliveTimeout(),
+ Poll.APR_POLLIN);
+- } else {
+- // Close the socket since this is
+- // the end of not keep-alive request.
+- closeSocket(state.socket);
++ break;
++ }
+ }
+ }
+ }
+diff --git a/java/org/apache/tomcat/util/net/Nio2Endpoint.java b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+index 73605e8..a8231bf 100644
+--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
++++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+@@ -536,17 +536,24 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel> {
+ } catch (IOException e) {
+ // Ignore
+ }
+- if (attachment.keepAlive) {
+- if (!isInline()) {
++ if (isInline()) {
++ attachment.doneInline = true;
++ } else {
++ switch (attachment.keepAliveState) {
++ case NONE: {
++ getEndpoint().processSocket(Nio2SocketWrapper.this,
++ SocketEvent.DISCONNECT, false);
++ break;
++ }
++ case PIPELINED: {
++ getEndpoint().processSocket(Nio2SocketWrapper.this,
++ SocketEvent.OPEN_READ, true);
++ break;
++ }
++ case OPEN: {
+ awaitBytes();
+- } else {
+- attachment.doneInline = true;
++ break;
+ }
+- } else {
+- if (!isInline()) {
+- getEndpoint().processSocket(Nio2SocketWrapper.this, SocketEvent.DISCONNECT, false);
+- } else {
+- attachment.doneInline = true;
+ }
+ }
+ return;
+diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
+index 8775919..71dad75 100644
+--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
++++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
+@@ -917,16 +917,30 @@ public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
+ // responsible for registering the socket for the
+ // appropriate event(s) if sendfile completes.
+ if (!calledByProcessor) {
+- if (sd.keepAlive) {
+- if (log.isDebugEnabled()) {
+- log.debug("Connection is keep alive, registering back for OP_READ");
+- }
+- reg(sk,socketWrapper,SelectionKey.OP_READ);
+- } else {
++ switch (sd.keepAliveState) {
++ case NONE: {
+ if (log.isDebugEnabled()) {
+ log.debug("Send file connection is being closed");
+ }
+ close(sc, sk);
++ break;
++ }
++ case PIPELINED: {
++ if (log.isDebugEnabled()) {
++ log.debug("Connection is keep alive, processing pipe-lined data");
++ }
++ if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) {
++ close(sc, sk);
++ }
++ break;
++ }
++ case OPEN: {
++ if (log.isDebugEnabled()) {
++ log.debug("Connection is keep alive, registering back for OP_READ");
++ }
++ reg(sk,socketWrapper,SelectionKey.OP_READ);
++ break;
++ }
+ }
+ }
+ return SendfileState.DONE;
+diff --git a/java/org/apache/tomcat/util/net/SendfileDataBase.java b/java/org/apache/tomcat/util/net/SendfileDataBase.java
+index fc89b11..ca0ee3b 100644
+--- a/java/org/apache/tomcat/util/net/SendfileDataBase.java
++++ b/java/org/apache/tomcat/util/net/SendfileDataBase.java
+@@ -21,10 +21,10 @@ public abstract class SendfileDataBase {
+ /**
+ * Is the current request being processed on a keep-alive connection? This
+ * determines if the socket is closed once the send file completes or if
+- * processing continues with the next request on the connection (or waiting
+- * for that next request to arrive).
++ * processing continues with the next request on the connection or waiting
++ * for that next request to arrive.
+ */
+- public boolean keepAlive;
++ public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
+
+ /**
+ * The full path to the file that contains the data to be written to the
+diff --git a/java/org/apache/tomcat/util/net/SendfileKeepAliveState.java b/java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
+new file mode 100644
+index 0000000..b27a9f1
+--- /dev/null
++++ b/java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
+@@ -0,0 +1,39 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++package org.apache.tomcat.util.net;
++
++public enum SendfileKeepAliveState {
++
++ /**
++ * Keep-alive is not in use. The socket can be closed when the response has
++ * been written.
++ */
++ NONE,
++
++ /**
++ * Keep-alive is in use and there is pipelined data in the input buffer to
++ * be read as soon as the current response has been written.
++ */
++ PIPELINED,
++
++ /**
++ * Keep-alive is in use. The socket should be added to the poller (or
++ * equivalent) to await more data as soon as the current response has been
++ * written.
++ */
++ OPEN
++}
diff --git a/debian/patches/CVE-2017-5648.patch b/debian/patches/CVE-2017-5648.patch
new file mode 100644
index 0000000..7e5ebb6
--- /dev/null
+++ b/debian/patches/CVE-2017-5648.patch
@@ -0,0 +1,64 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 11 Apr 2017 23:48:23 +0200
+Subject: CVE-2017-5648
+
+Origin: http://svn.apache.org/r1788932
+---
+ java/org/apache/catalina/authenticator/FormAuthenticator.java | 11 +++++------
+ java/org/apache/catalina/core/StandardHostValve.java | 4 ++--
+ 2 files changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
+index e5f5854..b3056a0 100644
+--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
++++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
+@@ -427,9 +427,9 @@ public class FormAuthenticator
+ RequestDispatcher disp =
+ context.getServletContext().getRequestDispatcher(loginPage);
+ try {
+- if (context.fireRequestInitEvent(request)) {
++ if (context.fireRequestInitEvent(request.getRequest())) {
+ disp.forward(request.getRequest(), response);
+- context.fireRequestDestroyEvent(request);
++ context.fireRequestDestroyEvent(request.getRequest());
+ }
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+@@ -471,12 +471,11 @@ public class FormAuthenticator
+ }
+
+ RequestDispatcher disp =
+- context.getServletContext().getRequestDispatcher
+- (config.getErrorPage());
++ context.getServletContext().getRequestDispatcher(config.getErrorPage());
+ try {
+- if (context.fireRequestInitEvent(request)) {
++ if (context.fireRequestInitEvent(request.getRequest())) {
+ disp.forward(request.getRequest(), response);
+- context.fireRequestDestroyEvent(request);
++ context.fireRequestDestroyEvent(request.getRequest());
+ }
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+diff --git a/java/org/apache/catalina/core/StandardHostValve.java b/java/org/apache/catalina/core/StandardHostValve.java
+index 8fe3e1a..b08deab 100644
+--- a/java/org/apache/catalina/core/StandardHostValve.java
++++ b/java/org/apache/catalina/core/StandardHostValve.java
+@@ -123,7 +123,7 @@ final class StandardHostValve extends ValveBase {
+ try {
+ context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
+
+- if (!asyncAtStart && !context.fireRequestInitEvent(request)) {
++ if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
+ // Don't fire listeners during async processing (the listener
+ // fired for the request that called startAsync()).
+ // If a request init listener throws an exception, the request
+@@ -179,7 +179,7 @@ final class StandardHostValve extends ValveBase {
+ }
+
+ if (!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) {
+- context.fireRequestDestroyEvent(request);
++ context.fireRequestDestroyEvent(request.getRequest());
+ }
+ } finally {
+ // Access a session (if present) to update last accessed time, based
diff --git a/debian/patches/CVE-2017-5650.patch b/debian/patches/CVE-2017-5650.patch
new file mode 100644
index 0000000..d015624
--- /dev/null
+++ b/debian/patches/CVE-2017-5650.patch
@@ -0,0 +1,25 @@
+From: Markus Koschany <apo at debian.org>
+Date: Wed, 12 Apr 2017 00:00:50 +0200
+Subject: CVE-2017-5650
+
+Origin: http://svn.apache.org/r1788480
+---
+ java/org/apache/coyote/http2/Http2UpgradeHandler.java | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+index 03c5c25..0d7d9d5 100644
+--- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
++++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+@@ -983,6 +983,11 @@ public class Http2UpgradeHandler extends AbstractStream implements InternalHttpU
+
+ private void close() {
+ connectionState.set(ConnectionState.CLOSED);
++ for (Stream stream : streams.values()) {
++ // The connection is closing. Close the associated streams as no
++ // longer required.
++ stream.receiveReset(Http2Error.CANCEL.getCode());
++ }
+ try {
+ socketWrapper.close();
+ } catch (IOException ioe) {
diff --git a/debian/patches/CVE-2017-5651.patch b/debian/patches/CVE-2017-5651.patch
new file mode 100644
index 0000000..5ac1c52
--- /dev/null
+++ b/debian/patches/CVE-2017-5651.patch
@@ -0,0 +1,156 @@
+From: Markus Koschany <apo at debian.org>
+Date: Wed, 12 Apr 2017 00:11:24 +0200
+Subject: CVE-2017-5651
+
+Origin: http://svn.apache.org/r1788546
+---
+ java/org/apache/coyote/http11/Http11Processor.java | 52 ++++++++++------------
+ 1 file changed, 24 insertions(+), 28 deletions(-)
+
+diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
+index e260a39..99997e8 100644
+--- a/java/org/apache/coyote/http11/Http11Processor.java
++++ b/java/org/apache/coyote/http11/Http11Processor.java
+@@ -58,6 +58,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint;
+ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+ import org.apache.tomcat.util.net.SSLSupport;
+ import org.apache.tomcat.util.net.SendfileDataBase;
++import org.apache.tomcat.util.net.SendfileState;
+ import org.apache.tomcat.util.net.SendfileKeepAliveState;
+ import org.apache.tomcat.util.net.SocketWrapperBase;
+ import org.apache.tomcat.util.res.StringManager;
+@@ -659,9 +660,10 @@ public class Http11Processor extends AbstractProcessor {
+ openSocket = false;
+ readComplete = true;
+ boolean keptAlive = false;
++ SendfileState sendfileState = SendfileState.DONE;
+
+- while (!getErrorState().isError() && keepAlive && !isAsync() &&
+- upgradeToken == null && !endpoint.isPaused()) {
++ while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
++ sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
+
+ // Parsing the request header
+ try {
+@@ -850,9 +852,7 @@ public class Http11Processor extends AbstractProcessor {
+
+ rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+
+- if (breakKeepAliveLoop(socketWrapper)) {
+- break;
+- }
++ sendfileState = processSendfile(socketWrapper);
+ }
+
+ rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+@@ -864,7 +864,7 @@ public class Http11Processor extends AbstractProcessor {
+ } else if (isUpgrade()) {
+ return SocketState.UPGRADING;
+ } else {
+- if (sendfileData != null) {
++ if (sendfileState == SendfileState.PENDING) {
+ return SocketState.SENDFILE;
+ } else {
+ if (openSocket) {
+@@ -940,7 +940,6 @@ public class Http11Processor extends AbstractProcessor {
+ http11 = true;
+ http09 = false;
+ contentDelimitation = false;
+- sendfileData = null;
+
+ if (endpoint.isSSLEnabled()) {
+ request.scheme().setString("https");
+@@ -1147,15 +1146,14 @@ public class Http11Processor extends AbstractProcessor {
+ }
+
+ // Sendfile support
+- boolean sendingWithSendfile = false;
+ if (endpoint.getUseSendfile()) {
+- sendingWithSendfile = prepareSendfile(outputFilters);
++ prepareSendfile(outputFilters);
+ }
+
+ // Check for compression
+ boolean isCompressable = false;
+ boolean useCompression = false;
+- if (entityBody && (compressionLevel > 0) && !sendingWithSendfile) {
++ if (entityBody && (compressionLevel > 0) && sendfileData == null) {
+ isCompressable = isCompressable();
+ if (isCompressable) {
+ useCompression = useCompression();
+@@ -1297,10 +1295,12 @@ public class Http11Processor extends AbstractProcessor {
+ return connection.equals(Constants.CLOSE);
+ }
+
+- private boolean prepareSendfile(OutputFilter[] outputFilters) {
++ private void prepareSendfile(OutputFilter[] outputFilters) {
+ String fileName = (String) request.getAttribute(
+ org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR);
+- if (fileName != null) {
++ if (fileName == null) {
++ sendfileData = null;
++ } else {
+ // No entity body sent here
+ outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
+ contentDelimitation = true;
+@@ -1309,9 +1309,7 @@ public class Http11Processor extends AbstractProcessor {
+ long end = ((Long) request.getAttribute(
+ org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue();
+ sendfileData = socketWrapper.createSendfileData(fileName, pos, end - pos);
+- return true;
+ }
+- return false;
+ }
+
+ /**
+@@ -1592,14 +1590,15 @@ public class Http11Processor extends AbstractProcessor {
+
+
+ /**
+- * Checks to see if the keep-alive loop should be broken, performing any
+- * processing (e.g. sendfile handling) that may have an impact on whether
+- * or not the keep-alive loop should be broken.
+ *
+- * @return true if the keep-alive loop should be broken
++ * Trigger sendfile processing if required.
++ *
++ * @return The state of send file processing
+ */
+- private boolean breakKeepAliveLoop(SocketWrapperBase<?> socketWrapper) {
++ private SendfileState processSendfile(SocketWrapperBase<?> socketWrapper) {
+ openSocket = keepAlive;
++ // Done is equivalent to sendfile not being used
++ SendfileState result = SendfileState.DONE;
+ // Do sendfile as needed: add socket to sendfile and end
+ if (sendfileData != null && !getErrorState().isError()) {
+ if (keepAlive) {
+@@ -1612,23 +1611,20 @@ public class Http11Processor extends AbstractProcessor {
+ sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
+ }
+
+- switch (socketWrapper.processSendfile(sendfileData)) {
+- case DONE:
+- // If sendfile is complete, no need to break keep-alive loop
+- sendfileData = null;
+- return false;
+- case PENDING:
+- return true;
++ result = socketWrapper.processSendfile(sendfileData);
++ switch (result) {
+ case ERROR:
+ // Write failed
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("http11processor.sendfile.error"));
+ }
+ setErrorState(ErrorState.CLOSE_CONNECTION_NOW, null);
+- return true;
++ //$FALL-THROUGH$
++ default:
++ sendfileData = null;
+ }
+ }
+- return false;
++ return result;
+ }
+
+
diff --git a/debian/patches/series b/debian/patches/series
index 1b36989..85528d8 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -8,3 +8,7 @@
0018-fix-manager-webapp.patch
0019-add-distribution-to-error-page.patch
0021-dont-test-unsupported-ciphers.patch
+CVE-2017-5647.patch
+CVE-2017-5648.patch
+CVE-2017-5650.patch
+CVE-2017-5651.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/tomcat8.git
More information about the pkg-java-commits
mailing list