CVE-2017-5651
Description
In Apache Tomcat 9.0.0.M1 to 9.0.0.M18 and 8.5.0 to 8.5.12, the refactoring of the HTTP connectors introduced a regression in the send file processing. If the send file processing completed quickly, it was possible for the Processor to be added to the processor cache twice. This could result in the same Processor being used for multiple requests which in turn could lead to unexpected errors and/or response mix-up.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.tomcat:tomcat-coyoteMaven | >= 9.0.0.M1, < 9.0.0.M19 | 9.0.0.M19 |
org.apache.tomcat:tomcat-coyoteMaven | >= 8.5.0, < 8.5.13 | 8.5.13 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 9.0.0.M1, < 9.0.0.M19 | 9.0.0.M19 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 8.5.0, < 8.5.13 | 8.5.13 |
Affected products
32cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*+ 30 more
- cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone1:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone10:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone11:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone12:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone13:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone14:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone15:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone16:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone17:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone18:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone2:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone3:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone4:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone5:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone6:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone7:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone8:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone9:*:*:*:*:*:*
- Apache Software Foundation/Apache Tomcatv5Range: 9.0.0.M1 to 9.0.0.M18
Patches
2494429ca2106Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=60918
2 files changed · +28 −28
java/org/apache/coyote/http11/Http11Processor.java+23 −28 modified@@ -58,6 +58,7 @@ 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.SocketWrapperBase; import org.apache.tomcat.util.res.StringManager; @@ -671,9 +672,10 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) 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 { @@ -862,9 +864,7 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - if (breakKeepAliveLoop(socketWrapper)) { - break; - } + sendfileState = processSendfile(socketWrapper); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); @@ -876,7 +876,7 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) } else if (isUpgrade()) { return SocketState.UPGRADING; } else { - if (sendfileData != null) { + if (sendfileState == SendfileState.PENDING) { return SocketState.SENDFILE; } else { if (openSocket) { @@ -952,7 +952,6 @@ private void prepareRequest() { http11 = true; http09 = false; contentDelimitation = false; - sendfileData = null; if (endpoint.isSSLEnabled()) { request.scheme().setString("https"); @@ -1159,15 +1158,14 @@ protected final void prepareResponse() throws IOException { } // Sendfile support - boolean sendingWithSendfile = false; if (endpoint.getUseSendfile()) { - sendingWithSendfile = prepareSendfile(outputFilters); + prepareSendfile(outputFilters); } // Check for compression boolean isCompressible = false; boolean useCompression = false; - if (entityBody && (compressionLevel > 0) && !sendingWithSendfile) { + if (entityBody && (compressionLevel > 0) && sendfileData == null) { isCompressible = isCompressible(); if (isCompressible) { useCompression = useCompression(); @@ -1309,10 +1307,12 @@ private static boolean isConnectionClose(MimeHeaders headers) { 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; @@ -1321,9 +1321,7 @@ private boolean prepareSendfile(OutputFilter[] outputFilters) { 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; } /** @@ -1604,34 +1602,31 @@ public boolean isUpgrade() { /** - * 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. + * Trigger sendfile processing if required. * - * @return true if the keep-alive loop should be broken + * @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()) { sendfileData.keepAlive = keepAlive; - 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; }
webapps/docs/changelog.xml+5 −0 modified@@ -107,6 +107,11 @@ Improve HPACK specification compliance by fixing some test failures reported by the h2spec tool written by Moto Ishizawa. (markt) </fix> + <fix> + <bug>60918</bug>: Fix sendfile processing error that could lead to + subsequent requests experiencing and <code>IllegalStateException</code>. + (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
9233d9d6a018Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=60918
2 files changed · +28 −28
java/org/apache/coyote/http11/Http11Processor.java+23 −28 modified@@ -55,6 +55,7 @@ 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.SocketWrapperBase; import org.apache.tomcat.util.res.StringManager; @@ -368,9 +369,10 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) openSocket = false; readComplete = true; boolean keptAlive = false; + SendfileState sendfileState = SendfileState.DONE; - while (!getErrorState().isError() && keepAlive && !isAsync() && - upgradeToken == null && !protocol.isPaused()) { + while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null && + sendfileState == SendfileState.DONE && !protocol.isPaused()) { // Parsing the request header try { @@ -561,9 +563,7 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - if (breakKeepAliveLoop(socketWrapper)) { - break; - } + sendfileState = processSendfile(socketWrapper); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); @@ -575,7 +575,7 @@ public SocketState service(SocketWrapperBase<?> socketWrapper) } else if (isUpgrade()) { return SocketState.UPGRADING; } else { - if (sendfileData != null) { + if (sendfileState == SendfileState.PENDING) { return SocketState.SENDFILE; } else { if (openSocket) { @@ -651,7 +651,6 @@ private void prepareRequest() { http11 = true; http09 = false; contentDelimitation = false; - sendfileData = null; if (protocol.isSSLEnabled()) { request.scheme().setString("https"); @@ -858,15 +857,14 @@ protected final void prepareResponse() throws IOException { } // Sendfile support - boolean sendingWithSendfile = false; if (protocol.getUseSendfile()) { - sendingWithSendfile = prepareSendfile(outputFilters); + prepareSendfile(outputFilters); } // Check for compression boolean isCompressible = false; boolean useCompression = false; - if (entityBody && (protocol.getCompressionLevel() > 0) && !sendingWithSendfile) { + if (entityBody && (protocol.getCompressionLevel() > 0) && sendfileData == null) { isCompressible = isCompressible(); if (isCompressible) { useCompression = useCompression(); @@ -1009,10 +1007,12 @@ private static boolean isConnectionClose(MimeHeaders headers) { 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; @@ -1021,9 +1021,7 @@ private boolean prepareSendfile(OutputFilter[] outputFilters) { 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; } /** @@ -1304,34 +1302,31 @@ public boolean isUpgrade() { /** - * 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. + * Trigger sendfile processing if required. * - * @return true if the keep-alive loop should be broken + * @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()) { sendfileData.keepAlive = keepAlive; - 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; }
webapps/docs/changelog.xml+5 −0 modified@@ -132,6 +132,11 @@ Improve HPACK specification compliance by fixing some test failures reported by the h2spec tool written by Moto Ishizawa. (markt) </fix> + <fix> + <bug>60918</bug>: Fix sendfile processing error that could lead to + subsequent requests experiencing and <code>IllegalStateException</code>. + (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
31- bz.apache.org/bugzilla/show_bug.cginvdIssue TrackingPatchWEB
- www.securityfocus.com/bid/97544nvdThird Party AdvisoryVDB Entry
- github.com/advisories/GHSA-9hg2-395j-83rmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2017-5651ghsaADVISORY
- www.oracle.com/technetwork/security-advisory/cpujul2017-3236622.htmlnvdWEB
- github.com/apache/tomcat/commit/494429ca210641b6b7affe89a2b0a6c0ff70109bghsaWEB
- github.com/apache/tomcat/commit/9233d9d6a018be4415d4d7d6cb4fe01176adf1a8ghsaWEB
- lists.apache.org/thread.html/343558d982879bf88ec20dbf707f8c11255f8e219e81d45c4f8d0551%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/343558d982879bf88ec20dbf707f8c11255f8e219e81d45c4f8d0551@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/5c0e00fd31efc11e147bf99d0f03c00a734447d3b131ab0818644cdb%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/5c0e00fd31efc11e147bf99d0f03c00a734447d3b131ab0818644cdb@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/6694538826b87522fb723d2dcedd537e14ebe0a381d92e5525a531d8%40%3Cannounce.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/6694538826b87522fb723d2dcedd537e14ebe0a381d92e5525a531d8@%3Cannounce.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/6af47120905aa7d8fe12f42e8ff2284fb338ba141d3b77b8c7cb61b3%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/6af47120905aa7d8fe12f42e8ff2284fb338ba141d3b77b8c7cb61b3@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/88855876c33f2f9c532ffb75bfee570ccf0b17ffa77493745af9a17a%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/88855876c33f2f9c532ffb75bfee570ccf0b17ffa77493745af9a17a@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/b5e3f51d28cd5d9b1809f56594f2cf63dcd6a90429e16ea9f83bbedc%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/b5e3f51d28cd5d9b1809f56594f2cf63dcd6a90429e16ea9f83bbedc@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/eb6efa8d59c45a7a9eff94c4b925467d3b3fec8ba7697f3daa314b04%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/eb6efa8d59c45a7a9eff94c4b925467d3b3fec8ba7697f3daa314b04@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r3bbb800a816d0a51eccc5a228c58736960a9fffafa581a225834d97d%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r3bbb800a816d0a51eccc5a228c58736960a9fffafa581a225834d97d@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r48c1444845fe15a823e1374674bfc297d5008a5453788099ea14caf0%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r48c1444845fe15a823e1374674bfc297d5008a5453788099ea14caf0@%3Cdev.tomcat.apache.org%3EghsaWEB
- security.gentoo.org/glsa/201705-09nvdWEB
- security.netapp.com/advisory/ntap-20180614-0001ghsaWEB
- web.archive.org/web/20170417124228/http://www.securityfocus.com/bid/97544ghsaWEB
- web.archive.org/web/20170420113605/http://www.securitytracker.com/id/1038219ghsaWEB
- www.securitytracker.com/id/1038219nvd
- security.netapp.com/advisory/ntap-20180614-0001/nvd
News mentions
0No linked articles in our index yet.