diff -u tomcat5.5-5.5.25/debian/changelog tomcat5.5-5.5.25/debian/changelog --- tomcat5.5-5.5.25/debian/changelog +++ tomcat5.5-5.5.25/debian/changelog @@ -1,3 +1,20 @@ +tomcat5.5 (5.5.25-5ubuntu1.1) hardy-security; urgency=low + + * SECURITY UPDATE: Fix information disclosure vulnerability that allowed to + access unauthorized content, fix directory traversal vulnerability that + could on specific configurations lead to the disclosure of sensitive + files, and fix two cross-site-scripting issues that could result in + arbitrary content being injected into the HTTP response. + * Security patches from upstream SVN, applied inline + (LP: #256802, LP: #256922, LP: #256926, LP: #270553) + * References + CVE-2008-1232 + CVE-2008-1947 + CVE-2008-2370 + CVE-2008-2938 + + -- Thierry Carrez Mon, 15 Sep 2008 17:13:15 +0200 + tomcat5.5 (5.5.25-5ubuntu1) hardy; urgency=low * Merge from Debian unstable (LP: #153672, LP: #159661, LP: #161882, only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java +++ tomcat5.5-5.5.25/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java @@ -448,11 +448,14 @@ buf[pos++] = Constants.SP; // Write message - String message = response.getMessage(); + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { + message = response.getMessage(); + } if (message == null) { write(getMessage(status)); } else { - write(message); + write(message.replace('\n', ' ').replace('\r', ' ')); } // End the response status line only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java +++ tomcat5.5-5.5.25/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java @@ -429,11 +429,14 @@ buf[pos++] = Constants.SP; // Write message - String message = response.getMessage(); + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { + message = response.getMessage(); + } if (message == null) { write(HttpMessages.getMessage(status)); } else { - write(message); + write(message.replace('\n', ' ').replace('\r', ' ')); } // End the response status line only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java +++ tomcat5.5-5.5.25/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java @@ -264,6 +264,13 @@ } } + // Check that the URI is still normalized + if (!checkNormalize(req.decodedURI())) { + res.setStatus(400); + res.setMessage("Invalid URI character encoding"); + throw new IOException("Invalid URI character encoding"); + } + // Parse cookies parseCookies(req, request); @@ -654,6 +661,67 @@ } + /** + * Check that the URI is normalized following character decoding. + *

+ * This method checks for "\", 0, "//", "/./" and "/../". This method will + * return false if sequences that are supposed to be normalized are still + * present in the URI. + * + * @param uriMB URI to be checked (should be chars) + */ + public static boolean checkNormalize(MessageBytes uriMB) { + + CharChunk uriCC = uriMB.getCharChunk(); + char[] c = uriCC.getChars(); + int start = uriCC.getStart(); + int end = uriCC.getEnd(); + + int pos = 0; + + // Check for '\' and 0 + for (pos = start; pos < end; pos++) { + if (c[pos] == '\\') { + return false; + } + if (c[pos] == 0) { + return false; + } + } + + // Check for "//" + for (pos = start; pos < (end - 1); pos++) { + if (c[pos] == '/') { + if (c[pos + 1] == '/') { + return false; + } + } + } + + // Check for ending with "/." or "/.." + if (((end - start) >= 2) && (c[end - 1] == '.')) { + if ((c[end - 2] == '/') + || ((c[end - 2] == '.') + && (c[end - 3] == '/'))) { + return false; + } + } + + // Check for "/./" + if (uriCC.indexOf("/./", 0, 3, 0) >= 0) { + return false; + } + + // Check for "/../" + if (uriCC.indexOf("/../", 0, 4, 0) >= 0) { + return false; + } + + return true; + + } + + // ------------------------------------------------------ Protected Methods only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/coyote/src/java/org/apache/coyote/Constants.java +++ tomcat5.5-5.5.25/connectors/coyote/src/java/org/apache/coyote/Constants.java @@ -53,4 +53,12 @@ public static final int STAGE_ENDED = 7; + /** + * If true, custom HTTP status messages will be used in headers. + */ + public static final boolean USE_CUSTOM_STATUS_MSG_IN_HEADER = + Boolean.valueOf(System.getProperty( + "org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER", + "false")).booleanValue(); + } only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java +++ tomcat5.5-5.5.25/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java @@ -942,7 +942,10 @@ // HTTP header contents responseHeaderMessage.appendInt(response.getStatus()); - String message = response.getMessage(); + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { + message = response.getMessage(); + } if (message == null){ message = HttpMessages.getMessage(response.getStatus()); } else { only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/connectors/jk/java/org/apache/jk/common/JkInputStream.java +++ tomcat5.5-5.5.25/connectors/jk/java/org/apache/jk/common/JkInputStream.java @@ -279,7 +279,10 @@ outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS); outputMsg.appendInt( res.getStatus() ); - String message=res.getMessage(); + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { + message = res.getMessage(); + } if( message==null ){ message= HttpMessages.getMessage(res.getStatus()); } else { only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java +++ tomcat5.5-5.5.25/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java @@ -379,10 +379,21 @@ throw new IllegalArgumentException (sm.getString ("applicationContext.requestDispatcher.iae", path)); + + // Get query string + String queryString = null; + int pos = path.indexOf('?'); + if (pos >= 0) { + queryString = path.substring(pos + 1); + path = path.substring(0, pos); + } + path = normalize(path); if (path == null) return (null); + pos = path.length(); + // Retrieve the thread local URI MessageBytes uriMB = (MessageBytes) localUriMB.get(); if (uriMB == null) { @@ -394,15 +405,6 @@ uriMB.recycle(); } - // Get query string - String queryString = null; - int pos = path.indexOf('?'); - if (pos >= 0) { - queryString = path.substring(pos + 1); - } else { - pos = path.length(); - } - // Retrieve the thread local mapping data MappingData mappingData = (MappingData) localMappingData.get(); if (mappingData == null) { only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java +++ tomcat5.5-5.5.25/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java @@ -119,8 +119,7 @@ || (requestPathMB.equalsIgnoreCase("/META-INF")) || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { - String requestURI = request.getDecodedRequestURI(); - notFound(requestURI, response); + notFound(response); return; } @@ -136,8 +135,7 @@ // Select the Wrapper to be used for this Request Wrapper wrapper = request.getWrapper(); if (wrapper == null) { - String requestURI = request.getDecodedRequestURI(); - notFound(requestURI, response); + notFound(response); return; } @@ -206,13 +204,12 @@ * application, but currently that code runs at the wrapper level rather * than the context level. * - * @param requestURI The request URI for the requested resource * @param response The response we are creating */ - private void notFound(String requestURI, HttpServletResponse response) { + private void notFound(HttpServletResponse response) { try { - response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI); + response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (IllegalStateException e) { ; } catch (IOException e) { only in patch2: unchanged: --- tomcat5.5-5.5.25.orig/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java +++ tomcat5.5-5.5.25/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.net.URLEncoder; import java.text.MessageFormat; import java.util.Iterator; import java.util.Map; @@ -276,17 +277,20 @@ args = new Object[7]; args[0] = response.encodeURL (request.getContextPath() + - "/html/start?name=" + hostName); + "/html/start?name=" + + URLEncoder.encode(hostName, "UTF-8")); args[1] = hostsStart; args[2] = response.encodeURL (request.getContextPath() + - "/html/stop?name=" + hostName); + "/html/stop?name=" + + URLEncoder.encode(hostName, "UTF-8")); args[3] = hostsStop; args[4] = response.encodeURL (request.getContextPath() + - "/html/remove?name=" + hostName); + "/html/remove?name=" + + URLEncoder.encode(hostName, "UTF-8")); args[5] = hostsRemove; - args[6] = hostName; + args[6] = RequestUtil.filter(hostName); if (host == this.host) { writer.print(MessageFormat.format( MANAGER_HOST_ROW_BUTTON_SECTION, args));