From 1af9a1c4668f23fa7390f82e120a61d5e38a3c2b Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Mar 20 2014 21:54:11 +0000 Subject: import tomcat-7.0.42-4.el7.src.rpm --- diff --git a/.tomcat.metadata b/.tomcat.metadata index 3f0cce6..0f4bcad 100644 --- a/.tomcat.metadata +++ b/.tomcat.metadata @@ -1 +1 @@ -df0facd5b89243fbda74c91861c29c4039b9cd7d SOURCES/apache-tomcat-7.0.40-src.tar.gz +3f1061428dc6274e5b6159ed06462702e0550bd1 SOURCES/apache-tomcat-7.0.42-src.tar.gz diff --git a/SOURCES/tomcat-7.0.42-CVE-2013-4286.patch b/SOURCES/tomcat-7.0.42-CVE-2013-4286.patch new file mode 100644 index 0000000..5555cfb --- /dev/null +++ b/SOURCES/tomcat-7.0.42-CVE-2013-4286.patch @@ -0,0 +1,196 @@ +--- java/org/apache/coyote/ajp/AbstractAjpProcessor.java.orig 2014-03-14 17:13:46.228345000 -0400 ++++ java/org/apache/coyote/ajp/AbstractAjpProcessor.java 2014-03-18 13:54:13.570758000 -0400 +@@ -25,6 +25,8 @@ + import java.security.cert.X509Certificate; + import java.util.concurrent.atomic.AtomicBoolean; + ++import javax.servlet.http.HttpServletResponse; ++ + import org.apache.coyote.AbstractProcessor; + import org.apache.coyote.ActionCode; + import org.apache.coyote.AsyncContextCallback; +@@ -651,7 +653,7 @@ + + // Set this every time in case limit has been changed via JMX + headers.setLimit(endpoint.getMaxHeaderCount()); +- ++ boolean contentLengthSet = false; + int hCount = requestHeaderMessage.getInt(); + for(int i = 0 ; i < hCount ; i++) { + String hName = null; +@@ -686,10 +688,15 @@ + + if (hId == Constants.SC_REQ_CONTENT_LENGTH || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { +- // just read the content-length header, so set it + long cl = vMB.getLong(); +- if(cl < Integer.MAX_VALUE) +- request.setContentLength( (int)cl ); ++ if (contentLengthSet) { ++ response.setStatus(HttpServletResponse.SC_BAD_REQUEST); ++ error = true; ++ } else { ++ contentLengthSet = true; ++ // Set the content-length header for the request ++ request.setContentLength((int)cl); ++ } + } else if (hId == Constants.SC_REQ_CONTENT_TYPE || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { + // just read the content-type header, so set it +--- java/org/apache/coyote/http11/AbstractHttp11Processor.java.orig 2014-03-14 17:13:46.514347000 -0400 ++++ java/org/apache/coyote/http11/AbstractHttp11Processor.java 2014-03-14 17:13:46.353345000 -0400 +@@ -1277,10 +1277,20 @@ + + // Parse content-length header + long contentLength = request.getContentLengthLong(); +- if (contentLength >= 0 && !contentDelimitation) { +- getInputBuffer().addActiveFilter +- (inputFilters[Constants.IDENTITY_FILTER]); +- contentDelimitation = true; ++ if (contentLength >= 0) { ++ if (contentDelimitation) { ++ // contentDelimitation being true at this point indicates that ++ // chunked encoding is being used but chunked encoding should ++ // not be used with a content length. RFC 2616, section 4.4, ++ // bullet 3 states Content-Length must be ignored in this case - ++ // so remove it. ++ headers.removeHeader("content-length"); ++ request.setContentLength(-1); ++ } else { ++ getInputBuffer().addActiveFilter ++ (inputFilters[Constants.IDENTITY_FILTER]); ++ contentDelimitation = true; ++ } + } + + MessageBytes valueMB = headers.getValue("host"); +--- test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java.orig 2014-03-14 17:13:52.878367000 -0400 ++++ test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java 2014-03-14 17:21:43.278956000 -0400 +@@ -90,6 +90,61 @@ + ajpClient.disconnect(); + } + ++ @Test ++ public void testPost() throws Exception { ++ doTestPost(false, HttpServletResponse.SC_OK); ++ } ++ ++ public void testPostMultipleContentLength() throws Exception { ++ // Multiple content lengths ++ doTestPost(true, HttpServletResponse.SC_BAD_REQUEST); ++ } ++ ++ ++ public void doTestPost(boolean multipleCL, int expectedStatus) ++ throws Exception { ++ Tomcat tomcat = getTomcatInstance(); ++ // Use the normal Tomcat ROOT context ++ File root = new File("test/webapp-3.0"); ++ tomcat.addWebapp("", root.getAbsolutePath()); ++ tomcat.start(); ++ SimpleAjpClient ajpClient = new SimpleAjpClient(); ++ ajpClient.setPort(getPort()); ++ ajpClient.connect(); ++ ++ validateCpong(ajpClient.cping()); ++ ++ TesterAjpMessage forwardMessage = ++ ajpClient.createForwardMessage("/echo-params.jsp", 4); ++ forwardMessage.addHeader(0xA008, "9"); ++ if (multipleCL) { ++ forwardMessage.addHeader(0xA008, "99"); ++ } ++ forwardMessage.addHeader(0xA007, "application/x-www-form-urlencoded"); ++ forwardMessage.end(); ++ TesterAjpMessage bodyMessage = ++ ajpClient.createBodyMessage("test=data".getBytes()); ++ ++ TesterAjpMessage responseHeaders = ++ ajpClient.sendMessage(forwardMessage, bodyMessage); ++ ++ validateResponseHeaders(responseHeaders, expectedStatus); ++ if (expectedStatus == HttpServletResponse.SC_OK) { ++ // Expect 3 messages: headers, body, end for a valid request ++ TesterAjpMessage responseBody = ajpClient.readMessage(); ++ validateResponseBody(responseBody, "test - data"); ++ validateResponseEnd(ajpClient.readMessage(), true); ++ // Double check the connection is still open ++ validateCpong(ajpClient.cping()); ++ } else { ++ // Expect 2 messages: headers, end for an invalid request ++ validateResponseEnd(ajpClient.readMessage(), false); ++ } ++ ++ ajpClient.disconnect(); ++ } ++ ++ + /** + * Process response header packet and checks the status. Any other data is + * ignored. +--- test/org/apache/coyote/http11/TestAbstractHttp11Processor.java.orig 2014-03-14 17:13:52.946367000 -0400 ++++ test/org/apache/coyote/http11/TestAbstractHttp11Processor.java 2014-03-14 17:13:52.925368000 -0400 +@@ -87,7 +87,7 @@ + "Transfer-encoding: buffered" + SimpleHttpClient.CRLF + + "Content-Length: 9" + SimpleHttpClient.CRLF + + "Content-Type: application/x-www-form-urlencoded" + +- SimpleHttpClient.CRLF + ++ SimpleHttpClient.CRLF + + SimpleHttpClient.CRLF + + "test=data"; + +@@ -99,6 +99,54 @@ + assertTrue(client.isResponse501()); + } + ++ @Test ++ public void testWithTEChunked() throws Exception { ++ doTestWithTEChunked(false); ++ } ++ ++ @Test ++ public void testWithTEChunkedWithCL() throws Exception { ++ // Should be ignored ++ doTestWithTEChunked(true); ++ } ++ ++ private void doTestWithTEChunked(boolean withCL) ++ throws Exception { ++ ++ Tomcat tomcat = getTomcatInstance(); ++ ++ // Use the normal Tomcat ROOT context ++ File root = new File("test/webapp-3.0"); ++ tomcat.addWebapp("", root.getAbsolutePath()); ++ ++ tomcat.start(); ++ ++ String request = ++ "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF + ++ "Host: any" + SimpleHttpClient.CRLF + ++ (withCL ? "Content-length: 1" + SimpleHttpClient.CRLF : "") + ++ "Transfer-encoding: chunked" + SimpleHttpClient.CRLF + ++ "Content-Type: application/x-www-form-urlencoded" + ++ SimpleHttpClient.CRLF + ++ "Connection: close" + SimpleHttpClient.CRLF + ++ SimpleHttpClient.CRLF + ++ "9" + SimpleHttpClient.CRLF + ++ "test=data" + SimpleHttpClient.CRLF + ++ "0" + SimpleHttpClient.CRLF + ++ SimpleHttpClient.CRLF; ++ ++ Client client = new Client(tomcat.getConnector().getLocalPort()); ++ client.setRequest(new String[] {request}); ++ ++ client.connect(); ++ client.processRequest(); ++ assertTrue(client.isResponse200()); ++ assertTrue(client.getResponseBody().contains("test - data")); ++ } ++ ++ ++ ++ + + @Test + public void testWithTEIdentity() throws Exception { diff --git a/SOURCES/tomcat-7.0.42-CVE-2013-4322.patch b/SOURCES/tomcat-7.0.42-CVE-2013-4322.patch new file mode 100644 index 0000000..d814c39 --- /dev/null +++ b/SOURCES/tomcat-7.0.42-CVE-2013-4322.patch @@ -0,0 +1,365 @@ +--- java/org/apache/coyote/http11/AbstractHttp11Processor.java.orig 2014-03-17 16:00:40.592415000 -0400 ++++ java/org/apache/coyote/http11/AbstractHttp11Processor.java 2014-03-18 13:39:06.789696000 -0400 +@@ -684,13 +684,14 @@ + /** + * Initialize standard input and output filters. + */ +- protected void initializeFilters(int maxTrailerSize) { ++ protected void initializeFilters(int maxTrailerSize, int maxExtensionSize) { + // Create and add the identity filters. + getInputBuffer().addFilter(new IdentityInputFilter()); + getOutputBuffer().addFilter(new IdentityOutputFilter()); + + // Create and add the chunked filters. +- getInputBuffer().addFilter(new ChunkedInputFilter(maxTrailerSize)); ++ getInputBuffer().addFilter( ++ new ChunkedInputFilter(maxTrailerSize, maxExtensionSize)); + getOutputBuffer().addFilter(new ChunkedOutputFilter()); + + // Create and add the void filters. +--- java/org/apache/coyote/http11/AbstractHttp11Protocol.java.orig 2014-03-17 16:00:57.458467000 -0400 ++++ java/org/apache/coyote/http11/AbstractHttp11Protocol.java 2014-03-17 16:40:11.035409000 -0400 +@@ -151,7 +151,15 @@ + this.maxTrailerSize = maxTrailerSize; + } + +- ++ /** ++ * Maximum size of extension information in chunked encoding ++ */ ++ private int maxExtensionSize = 8192; ++ public int getMaxExtensionSize() { return maxExtensionSize; } ++ public void setMaxExtensionSize(int maxExtensionSize) { ++ this.maxExtensionSize = maxExtensionSize; ++ } ++ + /** + * This field indicates if the protocol is treated as if it is secure. This + * normally means https is being used but can be used to fake https e.g +--- java/org/apache/coyote/http11/Http11AprProcessor.java.orig 2014-03-17 16:01:22.889559000 -0400 ++++ java/org/apache/coyote/http11/Http11AprProcessor.java 2014-03-17 16:43:14.716027000 -0400 +@@ -58,7 +58,7 @@ + + + public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint, +- int maxTrailerSize) { ++ int maxTrailerSize, int maxExtensionSize) { + + super(endpoint); + +@@ -68,7 +68,7 @@ + outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize); + response.setOutputBuffer(outputBuffer); + +- initializeFilters(maxTrailerSize); ++ initializeFilters(maxTrailerSize, maxExtensionSize); + } + + +--- java/org/apache/coyote/http11/Http11AprProtocol.java.orig 2014-03-17 16:10:16.268358000 -0400 ++++ java/org/apache/coyote/http11/Http11AprProtocol.java 2014-03-17 16:50:17.428466000 -0400 +@@ -294,7 +294,7 @@ + protected Http11AprProcessor createProcessor() { + Http11AprProcessor processor = new Http11AprProcessor( + proto.getMaxHttpHeaderSize(), (AprEndpoint)proto.endpoint, +- proto.getMaxTrailerSize()); ++ proto.getMaxTrailerSize(), proto.getMaxExtensionSize()); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); + processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); +--- java/org/apache/coyote/http11/Http11NioProcessor.java.orig 2014-03-17 16:02:20.016748000 -0400 ++++ java/org/apache/coyote/http11/Http11NioProcessor.java 2014-03-17 16:51:55.623782000 -0400 +@@ -63,7 +63,7 @@ + + + public Http11NioProcessor(int maxHttpHeaderSize, NioEndpoint endpoint, +- int maxTrailerSize) { ++ int maxTrailerSize, int maxExtensionSize) { + + super(endpoint); + +@@ -73,7 +73,7 @@ + outputBuffer = new InternalNioOutputBuffer(response, maxHttpHeaderSize); + response.setOutputBuffer(outputBuffer); + +- initializeFilters(maxTrailerSize); ++ initializeFilters(maxTrailerSize, maxExtensionSize); + } + + +--- java/org/apache/coyote/http11/Http11NioProtocol.java.orig 2014-03-17 16:07:26.027787000 -0400 ++++ java/org/apache/coyote/http11/Http11NioProtocol.java 2014-03-17 16:53:09.198025000 -0400 +@@ -260,7 +260,7 @@ + public Http11NioProcessor createProcessor() { + Http11NioProcessor processor = new Http11NioProcessor( + proto.getMaxHttpHeaderSize(), (NioEndpoint)proto.endpoint, +- proto.getMaxTrailerSize()); ++ proto.getMaxTrailerSize(), proto.getMaxExtensionSize()); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); + processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); +--- java/org/apache/coyote/http11/Http11Processor.java.orig 2014-03-17 16:07:45.099837000 -0400 ++++ java/org/apache/coyote/http11/Http11Processor.java 2014-03-18 12:42:34.018260000 -0400 +@@ -50,7 +50,7 @@ + + + public Http11Processor(int headerBufferSize, JIoEndpoint endpoint, +- int maxTrailerSize) { ++ int maxTrailerSize, int maxExtensionSize) { + + super(endpoint); + +@@ -60,7 +60,7 @@ + outputBuffer = new InternalOutputBuffer(response, headerBufferSize); + response.setOutputBuffer(outputBuffer); + +- initializeFilters(maxTrailerSize); ++ initializeFilters(maxTrailerSize, maxExtensionSize); + } + + +--- java/org/apache/coyote/http11/Http11Protocol.java.orig 2014-03-17 16:08:00.058113000 -0400 ++++ java/org/apache/coyote/http11/Http11Protocol.java 2014-03-17 16:56:04.194609000 -0400 +@@ -164,7 +164,7 @@ + protected Http11Processor createProcessor() { + Http11Processor processor = new Http11Processor( + proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint, +- proto.getMaxTrailerSize()); ++ proto.getMaxTrailerSize(), proto.getMaxExtensionSize()); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); + processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); +--- java/org/apache/coyote/http11/filters/ChunkedInputFilter.java.orig 2014-03-17 16:08:12.213985000 -0400 ++++ java/org/apache/coyote/http11/filters/ChunkedInputFilter.java 2014-03-18 13:13:49.468583000 -0400 +@@ -118,9 +118,29 @@ + */ + private Request request; + ++ ++ /** ++ * Limit for extension size. ++ */ ++ private final long maxExtensionSize; ++ ++ ++ /** ++ * Limit for trailer size. ++ */ ++ private int maxTrailerSize; ++ ++ ++ /** ++ * Size of extensions processed for this request. ++ */ ++ private long extensionSize; ++ + // ----------------------------------------------------------- Constructors +- public ChunkedInputFilter(int maxTrailerSize) { ++ public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize) { + this.trailingHeaders.setLimit(maxTrailerSize); ++ this.maxTrailerSize = maxTrailerSize; ++ this.maxExtensionSize = maxExtensionSize; + } + + // ---------------------------------------------------- InputBuffer Methods +@@ -250,6 +270,8 @@ + endChunk = false; + needCRLFParse = false; + trailingHeaders.recycle(); ++ trailingHeaders.setLimit(maxTrailerSize); ++ extensionSize = 0; + } + + +@@ -299,7 +321,7 @@ + int result = 0; + boolean eol = false; + boolean readDigit = false; +- boolean trailer = false; ++ boolean extension = false; + + while (!eol) { + +@@ -311,9 +333,13 @@ + if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { + parseCRLF(false); + eol = true; +- } else if (buf[pos] == Constants.SEMI_COLON) { +- trailer = true; +- } else if (!trailer) { ++ } else if (buf[pos] == Constants.SEMI_COLON && !extension) { ++ // First semi-colon marks the start of the extension. Further ++ // semi-colons may appear to separate multiple chunk-extensions. ++ // These need to be processed as part of parsing the extensions. ++ extension = true; ++ extensionSize++; ++ } else if (!extension) { + //don't read data after the trailer + int charValue = HexUtils.getDec(buf[pos]); + if (charValue != -1) { +@@ -325,13 +351,20 @@ + //in the chunked header + return false; + } +- } +- +- // Parsing the CRLF increments pos +- if (!eol) { +- pos++; +- } ++ } else { ++ // Extension 'parsing' ++ // Note that the chunk-extension is neither parsed nor ++ // validated. Currently it is simply ignored. ++ extensionSize++; ++ if (maxExtensionSize > -1 && extensionSize > maxExtensionSize) { ++ throw new IOException("maxExtensionSize exceeded"); ++ } ++ } ++ } + ++ // Parsing the CRLF increments pos ++ if (!eol) { ++ pos++; + } + + if (!readDigit) +@@ -489,12 +522,17 @@ + chr = buf[pos]; + if ((chr == Constants.SP) || (chr == Constants.HT)) { + pos++; ++ // If we swallow whitespace, make sure it counts towards the ++ // limit placed on trailing header size ++ int newlimit = trailingHeaders.getLimit() -1; ++ if (trailingHeaders.getEnd() > newlimit) { ++ throw new IOException("Exceeded maxTrailerSize"); ++ } ++ trailingHeaders.setLimit(newlimit); + } else { + space = false; + } +- + } +- + // Reading bytes until the end of the line + while (!eol) { + +--- test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java.orig 2014-03-17 16:08:33.031999000 -0400 ++++ test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java 2014-03-17 17:40:23.853592000 -0400 +@@ -41,6 +41,7 @@ + public class TestChunkedInputFilter extends TomcatBaseTest { + + private static final String LF = "\n"; ++ private static final int EXT_SIZE_LIMIT = 10; + + @Test + public void testChunkHeaderCRLF() throws Exception { +@@ -202,6 +203,79 @@ + assertTrue(client.isResponse500()); + } + ++ ++ @Test ++ public void testExtensionSizeLimitOneBelow() throws Exception { ++ doTestExtensionSizeLimit(EXT_SIZE_LIMIT - 1, true); ++ } ++ ++ ++ @Test ++ public void testExtensionSizeLimitExact() throws Exception { ++ doTestExtensionSizeLimit(EXT_SIZE_LIMIT, true); ++ } ++ ++ ++ @Test ++ public void testExtensionSizeLimitOneOver() throws Exception { ++ doTestExtensionSizeLimit(EXT_SIZE_LIMIT + 1, false); ++ } ++ ++ private void doTestExtensionSizeLimit(int len, boolean ok) ++ throws Exception { ++ // Setup Tomcat instance ++ Tomcat tomcat = getTomcatInstance(); ++ ++ tomcat.getConnector().setProperty( ++ "maxExtensionSize", Integer.toString(EXT_SIZE_LIMIT)); ++ ++ // Must have a real docBase - just use temp ++ Context ctx = ++ tomcat.addContext("", System.getProperty("java.io.tmpdir")); ++ ++ Tomcat.addServlet(ctx, "servlet", new EchoHeaderServlet()); ++ ctx.addServletMapping("/", "servlet"); ++ ++ tomcat.start(); ++ ++ String extName = ";foo="; ++ StringBuilder extValue = new StringBuilder(len); ++ for (int i = 0; i < (len - extName.length()); i++) { ++ extValue.append("x"); ++ } ++ ++ String[] request = new String[]{ ++ "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF + ++ "Host: any" + SimpleHttpClient.CRLF + ++ "Transfer-encoding: chunked" + SimpleHttpClient.CRLF + ++ "Content-Type: application/x-www-form-urlencoded" + ++ SimpleHttpClient.CRLF + ++ "Connection: close" + SimpleHttpClient.CRLF + ++ SimpleHttpClient.CRLF + ++ "3" + extName + extValue.toString() + SimpleHttpClient.CRLF + ++ "a=0" + SimpleHttpClient.CRLF + ++ "4" + SimpleHttpClient.CRLF + ++ "&b=1" + SimpleHttpClient.CRLF + ++ "0" + SimpleHttpClient.CRLF + ++ SimpleHttpClient.CRLF }; ++ ++ TrailerClient client = ++ new TrailerClient(tomcat.getConnector().getLocalPort()); ++ client.setRequest(request); ++ ++ client.connect(); ++ client.processRequest(); ++ ++ if (ok) { ++ assertTrue(client.isResponse200()); ++ } else { ++ assertTrue(client.isResponse500()); ++ } ++ } ++ ++ ++ ++ + @Test + public void testNoTrailingHeaders() throws Exception { + // Setup Tomcat instance +--- webapps/docs/changelog.xml.orig 2014-03-17 16:08:46.095050000 -0400 ++++ webapps/docs/changelog.xml 2014-03-17 17:44:14.163385000 -0400 +@@ -394,6 +394,11 @@ +
+ + ++ ++ Add support for limiting the size of chunk extensions when using chunked ++ encoding. (markt) ++ CVE-2013-4322 patch applied by Red Hat. ++ + + Update Tomcat's internal copy of Commons FileUpload to FileUpload 1.3. + (markt) +--- webapps/docs/config/http.xml.orig 2014-03-17 16:08:59.013101000 -0400 ++++ webapps/docs/config/http.xml 2014-03-17 18:10:13.965639000 -0400 +@@ -399,6 +399,12 @@ + and connections are not counted.

+ + ++ ++

Limits the total length of chunk extensions in chunked HTTP requests. ++ If the value is -1, no limit will be imposed. If not ++ specified, the default value of 8192 will be used.

++
++ + +

The maximum size of the request and response HTTP header, specified + in bytes. If not specified, this attribute is set to 8192 (8 KB).

diff --git a/SOURCES/tomcat-7.0.42-CVE-2014-0050.patch b/SOURCES/tomcat-7.0.42-CVE-2014-0050.patch new file mode 100644 index 0000000..8ce8a51 --- /dev/null +++ b/SOURCES/tomcat-7.0.42-CVE-2014-0050.patch @@ -0,0 +1,107 @@ +--- java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java.orig 2014-03-17 18:30:01.467636000 -0400 ++++ java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java 2014-03-17 18:37:43.992207000 -0400 +@@ -805,7 +805,7 @@ + || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) { + throw new InvalidContentTypeException(String.format( + "the request doesn't contain a %s or %s stream, content type header is %s", +- MULTIPART_FORM_DATA, MULTIPART_FORM_DATA, contentType)); ++ MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType)); + } + + InputStream input = ctx.getInputStream(); +@@ -816,8 +816,7 @@ + if (requestSize != -1 && requestSize > sizeMax) { + throw new SizeLimitExceededException(String.format( + "the request was rejected because its size (%s) exceeds the configured maximum (%s)", +- Long.valueOf(requestSize), +- Long.valueOf(sizeMax)), ++ Long.valueOf(requestSize), Long.valueOf(sizeMax)), + requestSize, sizeMax); + } + input = new LimitedInputStream(input, sizeMax) { +@@ -844,7 +843,14 @@ + } + + notifier = new MultipartStream.ProgressNotifier(listener, requestSize); +- multi = new MultipartStream(input, boundary, notifier); ++ try { ++ multi = new MultipartStream(input, boundary, notifier); ++ } catch (IllegalArgumentException iae) { ++ throw new InvalidContentTypeException(String.format( ++ "The boundary specified in the %s header is too long", ++ CONTENT_TYPE), iae); ++ } ++ + multi.setHeaderEncoding(charEncoding); + + skipPreamble = true; +@@ -1022,7 +1028,7 @@ + * detail message. + */ + public InvalidContentTypeException() { +- // Nothing to do. ++ super(); + } + + /** +@@ -1035,6 +1041,10 @@ + super(message); + } + ++ public InvalidContentTypeException(String msg, Throwable cause) { ++ super(msg, cause); ++ } ++ + } + + /** +--- java/org/apache/tomcat/util/http/fileupload/MultipartStream.java.orig 2014-03-17 18:30:01.512626000 -0400 ++++ java/org/apache/tomcat/util/http/fileupload/MultipartStream.java 2014-03-17 18:41:15.868033000 -0400 +@@ -278,8 +278,7 @@ + * @param pNotifier The notifier, which is used for calling the + * progress listener, if any. + * +- * @see #MultipartStream(InputStream, byte[], +- * MultipartStream.ProgressNotifier) ++ * @throws IllegalArgumentException If the buffer size is too small + */ + MultipartStream(InputStream input, + byte[] boundary, +@@ -292,8 +291,12 @@ + + // We prepend CR/LF to the boundary to chop trailing CR/LF from + // body-data tokens. +- this.boundary = new byte[boundary.length + BOUNDARY_PREFIX.length]; + this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length; ++ if (bufSize < this.boundaryLength + 1) { ++ throw new IllegalArgumentException( ++ "The buffer size specified for the MultipartStream is too small"); ++ } ++ this.boundary = new byte[this.boundaryLength]; + this.keepRegion = this.boundary.length; + System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, + BOUNDARY_PREFIX.length); +@@ -313,8 +316,7 @@ + * @param pNotifier An object for calling the progress listener, if any. + * + * +- * @see #MultipartStream(InputStream, byte[], int, +- * MultipartStream.ProgressNotifier) ++ * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier) + */ + MultipartStream(InputStream input, + byte[] boundary, +--- webapps/docs/changelog.xml.orig 2014-03-17 18:30:01.569656000 -0400 ++++ webapps/docs/changelog.xml 2014-03-17 18:44:11.967500000 -0400 +@@ -59,6 +59,11 @@ + + + ++ Fix CVE-2014-0050, a denial of service with a malicious, malformed ++ Content-Type header and multipart request processing. Fixed by merging ++ latest code (r1565163) from Commons FileUpload. (markt) ++ ++ + Enforce the restriction described in section 4.4 of the Servlet 3.0 + specification that requires the new pluggability methods only to be + available to ServletContextListeners defined in one of the diff --git a/SOURCES/tomcat-7.0.init b/SOURCES/tomcat-7.0.init deleted file mode 100644 index f5269f5..0000000 --- a/SOURCES/tomcat-7.0.init +++ /dev/null @@ -1,319 +0,0 @@ -#!/bin/bash -# -# tomcat This shell script takes care of starting and stopping Tomcat -# -# chkconfig: - 80 20 -# -### BEGIN INIT INFO -# Provides: tomcat -# Required-Start: $network $syslog -# Required-Stop: $network $syslog -# Default-Start: -# Default-Stop: -# Description: Release implementation for Servlet 3.0 and JSP 2.2 -# Short-Description: start and stop tomcat -### END INIT INFO -# -# - originally written by Henri Gomez, Keith Irwin, and Nicolas Mailhot -# - heavily rewritten by Deepak Bhole and Jason Corley -# - -## Source function library. -#. /etc/rc.d/init.d/functions -# Source LSB function library. -if [ -r /lib/lsb/init-functions ]; then - . /lib/lsb/init-functions -else - exit 1 -fi - -DISTRIB_ID=`lsb_release -i -s 2>/dev/null` - -NAME="$(basename $0)" -unset ISBOOT -if [ "${NAME:0:1}" = "S" -o "${NAME:0:1}" = "K" ]; then - NAME="${NAME:3}" - ISBOOT="1" -fi - -# For SELinux we need to use 'runuser' not 'su' -if [ -x "/sbin/runuser" ]; then - SU="/sbin/runuser -s /bin/sh" -else - SU="/bin/su -s /bin/sh" -fi - -# Get the tomcat config (use this for environment specific settings) -TOMCAT_CFG="/etc/tomcat/tomcat.conf" -if [ -r "$TOMCAT_CFG" ]; then - . $TOMCAT_CFG -fi - -# Get instance specific config file -if [ -r "/etc/sysconfig/${NAME}" ]; then - . /etc/sysconfig/${NAME} -fi - -# Define which connector port to use -CONNECTOR_PORT="${CONNECTOR_PORT:-8080}" - -# Path to the tomcat launch script -TOMCAT_SCRIPT="/usr/sbin/tomcat" - -# Tomcat program name -TOMCAT_PROG="${NAME}" - -# Define the tomcat username -TOMCAT_USER="${TOMCAT_USER:-tomcat}" - -# Define the tomcat log file -TOMCAT_LOG="${TOMCAT_LOG:-${CATALINA_HOME}/logs/${NAME}-initd.log}" - - -RETVAL="0" - -# Look for open ports, as the function name might imply -function findFreePorts() { - local isSet1="false" - local isSet2="false" - local isSet3="false" - local lower="8000" - randomPort1="0" - randomPort2="0" - randomPort3="0" - local -a listeners="( $( - netstat -ntl | \ - awk '/^tcp/ {gsub("(.)*:", "", $4); print $4}' - ) )" - while [ "$isSet1" = "false" ] || \ - [ "$isSet2" = "false" ] || \ - [ "$isSet3" = "false" ]; do - let port="${lower}+${RANDOM:0:4}" - if [ -z `expr " ${listeners[*]} " : ".*\( $port \).*"` ]; then - if [ "$isSet1" = "false" ]; then - export randomPort1="$port" - isSet1="true" - elif [ "$isSet2" = "false" ]; then - export randomPort2="$port" - isSet2="true" - elif [ "$isSet3" = "false" ]; then - export randomPort3="$port" - isSet3="true" - fi - fi - done -} - -function makeHomeDir() { - if [ ! -d "$CATALINA_HOME" ]; then - echo "$CATALINA_HOME does not exist, creating" - if [ ! -d "/usr/share/${NAME}" ]; then - mkdir /usr/share/${NAME} - cp -pLR /usr/share/tomcat/* /usr/share/${NAME} - fi - mkdir -p /var/log/${NAME} \ - /var/cache/${NAME} \ - /var/tmp/${NAME} - ln -fs /var/cache/${NAME} ${CATALINA_HOME}/work - ln -fs /var/tmp/${NAME} ${CATALINA_HOME}/temp - cp -pLR /usr/share/${NAME}/bin $CATALINA_HOME - cp -pLR /usr/share/${NAME}/conf $CATALINA_HOME - ln -fs /usr/share/java/tomcat ${CATALINA_HOME}/lib - ln -fs /usr/share/tomcat/webapps ${CATALINA_HOME}/webapps - chown ${TOMCAT_USER}:${TOMCAT_USER} /var/log/${NAME} - fi -} - -function parseOptions() { - options="" - options="$options $( - awk '!/^#/ && !/^$/ { ORS=" "; print "export ", $0, ";" }' \ - $TOMCAT_CFG - )" - if [ -r "/etc/sysconfig/${NAME}" ]; then - options="$options $( - awk '!/^#/ && !/^$/ { ORS=" "; - print "export ", $0, ";" }' \ - /etc/sysconfig/${NAME} - )" - fi - TOMCAT_SCRIPT="$options ${TOMCAT_SCRIPT}" -} - -# See how we were called. -function start() { - - echo -n "Starting ${TOMCAT_PROG}: " - if [ "$RETVAL" != "0" ]; then - log_failure_msg - return - fi - if [ -f "/var/lock/subsys/${NAME}" ]; then - if [ -s "/var/run/${NAME}.pid" ]; then - read kpid < /var/run/${NAME}.pid -# if checkpid $kpid 2>&1; then - if [ -d "/proc/${kpid}" ]; then - log_success_msg - if [ "$DISTRIB_ID" = "MandrivaLinux" ]; then - echo - fi - return 0 - fi - fi - fi - # fix permissions on the log and pid files - export CATALINA_PID="/var/run/${NAME}.pid" - touch $CATALINA_PID 2>&1 || RETVAL="4" - if [ "$RETVAL" -eq "0" -a "$?" -eq "0" ]; then - chown ${TOMCAT_USER}:${TOMCAT_USER} $CATALINA_PID - fi - [ "$RETVAL" -eq "0" ] && touch $TOMCAT_LOG 2>&1 || RETVAL="4" - if [ "$RETVAL" -eq "0" -a "$?" -eq "0" ]; then - chown ${TOMCAT_USER}:${TOMCAT_USER} $TOMCAT_LOG - fi - if [ "$CATALINA_HOME" != "/usr/share/tomcat" -a "$RETVAL" -eq "0" ]; then - # Create a tomcat directory if it doesn't exist - makeHomeDir - # If CATALINA_HOME doesn't exist modify port number so that - # multiple instances don't interfere with each other - findFreePorts - sed -i -e "s/8005/${randomPort1}/g" -e "s/8080/${CONNECTOR_PORT}/g" \ - -e "s/8009/${randomPort2}/g" -e "s/8443/${randomPort3}/g" \ - ${CATALINA_HOME}/conf/server.xml - fi - parseOptions - if [ "$RETVAL" -eq "0" -a "$SECURITY_MANAGER" = "true" ]; then - $SU - $TOMCAT_USER -c "${TOMCAT_SCRIPT} start-security" \ - >> ${TOMCAT_LOG} 2>&1 || RETVAL="4" - else - - [ "$RETVAL" -eq "0" ] && $SU - $TOMCAT_USER -c "${TOMCAT_SCRIPT} start" >> ${TOMCAT_LOG} 2>&1 || RETVAL="4" - fi - if [ "$RETVAL" -eq "0" ]; then - log_success_msg - touch /var/lock/subsys/${NAME} - else - log_failure_msg "Error code ${RETVAL}" - fi - if [ "$DISTRIB_ID" = "MandrivaLinux" ]; then - echo - fi -} - -function stop() { - echo -n "Stopping ${TOMCAT_PROG}: " - if [ -f "/var/lock/subsys/${NAME}" ]; then - parseOptions - if [ "$RETVAL" -eq "0" ]; then - touch /var/lock/subsys/${NAME} 2>&1 || RETVAL="4" - [ "$RETVAL" -eq "0" ] && $SU - $TOMCAT_USER -c "${TOMCAT_SCRIPT} stop" >> ${TOMCAT_LOG} 2>&1 || RETVAL="4" - fi - if [ "$RETVAL" -eq "0" ]; then - count="0" - if [ -s "/var/run/${NAME}.pid" ]; then - read kpid < /var/run/${NAME}.pid - until [ "$(ps --pid $kpid | grep -c $kpid)" -eq "0" ] || \ - [ "$count" -gt "$SHUTDOWN_WAIT" ]; do - if [ "$SHUTDOWN_VERBOSE" = "true" ]; then - echo "waiting for processes $kpid to exit" - fi - sleep 1 - let count="${count}+1" - done - if [ "$count" -gt "$SHUTDOWN_WAIT" ]; then - if [ "$SHUTDOWN_VERBOSE" = "true" ]; then - log_warning_msg "killing processes which did not stop after ${SHUTDOWN_WAIT} seconds" - fi - kill -9 $kpid - fi - log_success_msg - fi - rm -f /var/lock/subsys/${NAME} /var/run/${NAME}.pid - else - log_failure_msg - RETVAL="4" - fi - else - log_success_msg - RETVAL="0" - fi - if [ "$DISTRIB_ID" = "MandrivaLinux" ]; then - echo - fi -} - -function usage() -{ - echo "Usage: $0 {start|stop|restart|condrestart|try-restart|reload|force-reload|status|version}" - RETVAL="2" -} - -# See how we were called. -RETVAL="0" -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - start - ;; - condrestart|try-restart) - if [ -s "/var/run/${NAME}.pid" ]; then - stop - start - fi - ;; - reload) - RETVAL="3" - ;; - force-reload) - if [ -s "/var/run/${NAME}.pid" ]; then - stop - start - fi - ;; - status) - if [ -s "/var/run/${NAME}.pid" ]; then - read kpid < /var/run/${NAME}.pid - if [ -d "/proc/${kpid}" ]; then - log_success_msg "${NAME} (pid ${kpid}) is running..." - RETVAL="0" - else -# The pid file exists but the process is not running - log_warning_msg "PID file exists, but process is not running" - RETVAL="1" - fi - else - pid="$(/usr/bin/pgrep -d , -u ${TOMCAT_USER} -G ${TOMCAT_USER} java)" - if [ -z "$pid" ]; then -# status ${NAME} -# RETVAL="$?" - log_success_msg "${NAME} is stopped" - RETVAL="3" - else - log_success_msg "${NAME} (pid $pid) is running..." - RETVAL="0" - fi - fi - if [ -f /var/lock/subsys/${NAME} ]; then - pid="$(/usr/bin/pgrep -d , -u ${TOMCAT_USER} -G ${TOMCAT_USER} java)" -# The lockfile exists but the process is not running - if [ -z "$pid" ]; then - log_failure_msg "${NAME} lockfile exists but process is not running" - RETVAL="2" - fi - fi - ;; - version) - ${TOMCAT_SCRIPT} version - ;; - *) - usage - ;; -esac - -exit $RETVAL diff --git a/SPECS/tomcat.spec b/SPECS/tomcat.spec index ddb2cab..18db988 100644 --- a/SPECS/tomcat.spec +++ b/SPECS/tomcat.spec @@ -31,7 +31,7 @@ %global jspspec 2.2 %global major_version 7 %global minor_version 0 -%global micro_version 40 +%global micro_version 42 %global packdname apache-tomcat-%{version}-src %global servletspec 3.0 %global elspec 2.2 @@ -54,7 +54,7 @@ Name: tomcat Epoch: 0 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 2%{?dist} +Release: 4%{?dist} Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API Group: System Environment/Daemons @@ -62,7 +62,7 @@ License: ASL 2.0 URL: http://tomcat.apache.org/ Source0: http://www.apache.org/dist/tomcat/tomcat-%{major_version}/v%{version}/src/%{packdname}.tar.gz Source1: %{name}-%{major_version}.%{minor_version}.conf -Source2: %{name}-%{major_version}.%{minor_version}.init +#Source2: %{name}-%{major_version}.%{minor_version}.init Source3: %{name}-%{major_version}.%{minor_version}.sysconfig Source4: %{name}-%{major_version}.%{minor_version}.wrapper Source5: %{name}-%{major_version}.%{minor_version}.logrotate @@ -83,13 +83,16 @@ Source19: %{name}-%{major_version}.%{minor_version}-jsvc.wrapper Source20: %{name}-%{major_version}.%{minor_version}-jsvc.service -Patch0: %{name}-%{major_version}.%{minor_version}-bootstrap-MANIFEST.MF.patch -Patch1: %{name}-%{major_version}.%{minor_version}-tomcat-users-webapp.patch +Patch0: %{name}-%{major_version}.%{minor_version}-bootstrap-MANIFEST.MF.patch +Patch1: %{name}-%{major_version}.%{minor_version}-tomcat-users-webapp.patch +Patch2: %{name}-%{version}-CVE-2013-4286.patch +Patch3: %{name}-%{version}-CVE-2013-4322.patch +Patch4: %{name}-%{version}-CVE-2014-0050.patch BuildArch: noarch BuildRequires: ant -BuildRequires: ant-nodeps +#BuildRequires: ant-nodeps BuildRequires: ecj >= 1:4.2.1 BuildRequires: findutils BuildRequires: apache-commons-collections @@ -153,15 +156,15 @@ Requires: jpackage-utils %description javadoc Javadoc generated documentation for Apache Tomcat. -%package systemv -Group: System Environment/Daemons -Summary: Systemv scripts for Apache Tomcat -Requires: %{name} = %{epoch}:%{version}-%{release} -Requires(post): chkconfig -Requires(postun): chkconfig +#%package systemv +#Group: System Environment/Daemons +#Summary: Systemv scripts for Apache Tomcat +#Requires: %{name} = %{epoch}:%{version}-%{release} +#Requires(post): chkconfig +#Requires(postun): chkconfig -%description systemv -SystemV scripts to start and stop tomcat service +#%description systemv +#SystemV scripts to start and stop tomcat service %package jsvc Group: System Environment/Daemons @@ -242,11 +245,16 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name " %patch0 -p0 %patch1 -p0 +%patch2 -p0 +%patch3 -p0 +%patch4 -p0 + %{__ln_s} $(build-classpath jakarta-taglibs-core) webapps/examples/WEB-INF/lib/jstl.jar %{__ln_s} $(build-classpath jakarta-taglibs-standard) webapps/examples/WEB-INF/lib/standard.jar %build export OPT_JAR_LIST="xalan-j2-serializer" + # we don't care about the tarballs and we're going to replace # tomcat-dbcp.jar with apache-commons-{collections,dbcp,pool}-tomcat5.jar # so just create a dummy file for later removal @@ -358,8 +366,8 @@ popd -e "s|\@\@\@TCTEMP\@\@\@|%{tempdir}|g" \ -e "s|\@\@\@LIBDIR\@\@\@|%{_libdir}|g" %{SOURCE3} \ > ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name} -%{__install} -m 0644 %{SOURCE2} \ - ${RPM_BUILD_ROOT}%{_initrddir}/%{name} +#%{__install} -m 0644 %{SOURCE2} \ +# ${RPM_BUILD_ROOT}%{_initrddir}/%{name} %{__install} -m 0644 %{SOURCE4} \ ${RPM_BUILD_ROOT}%{_sbindir}/%{name} %{__install} -m 0644 %{SOURCE11} \ @@ -372,7 +380,7 @@ popd ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-jsvc.service %{__install} -m 0644 %{SOURCE18} \ ${RPM_BUILD_ROOT}%{_sbindir}/%{name}-jsvc-sysd -%{__ln_s} %{name} ${RPM_BUILD_ROOT}%{_sbindir}/d%{name} +# %{__ln_s} %{name} ${RPM_BUILD_ROOT}%{_sbindir}/d%{name} %{__sed} -e "s|\@\@\@TCLOG\@\@\@|%{logdir}|g" %{SOURCE5} \ > ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name} %{__sed} -e "s|\@\@\@TCHOME\@\@\@|%{homedir}|g" \ @@ -503,15 +511,15 @@ EOF # add the tomcat user and group %{_sbindir}/groupadd -g %{tcuid} -r tomcat 2>/dev/null || : %{_sbindir}/useradd -c "Apache Tomcat" -u %{tcuid} -g tomcat \ - -s /bin/nologin -r -d %{homedir} tomcat 2>/dev/null || : + -s /sbin/nologin -r -d %{homedir} tomcat 2>/dev/null || : %post # install but don't activate %systemd_post %{name}.service -%post systemv +#%post systemv # install but don't activate -/sbin/chkconfig --add %{name} +#/sbin/chkconfig --add %{name} %post jsp-%{jspspec}-api %{_sbindir}/update-alternatives --install %{_javadir}/jsp.jar jsp \ @@ -525,9 +533,11 @@ EOF %{_sbindir}/update-alternatives --install %{_javadir}/elspec.jar elspec \ %{_javadir}/%{name}-el-%{elspec}-api.jar 20300 -%preun systemv - %{_initrddir}/%{name} stop >/dev/null 2>&1 - /sbin/chkconfig --del %{name} +#%preun systemv +#if [ "$1" = "0" ]; then +# %{_initrddir}/%{name} stop >/dev/null 2>&1 +# /sbin/chkconfig --del %{name} +#fi %preun # clean tempdir and workdir on removal or upgrade @@ -665,10 +675,10 @@ fi %{appdir}/examples %{appdir}/sample -%files systemv -%defattr(755,root,root,0755) -%{_sbindir}/d%{name} -%{_initrddir}/%{name} +#%files systemv +#%defattr(755,root,root,0755) +#%{_sbindir}/d%{name} +#%{_initrddir}/%{name} %files jsvc %defattr(755,root,root,0755) @@ -676,7 +686,36 @@ fi %{_sbindir}/%{name}-jsvc-sysd %attr(0644,root,root) %{_unitdir}/%{name}-jsvc.service + %changelog +* Thu Mar 20 2014 David Knox - 0:7.0.42-4 +- Related: rhbz#1056696 correct packaging for sbin tomcat + +* Thu Mar 20 2014 David Knox - 0:7.0.42-3 +- Related: CVE-2013-4286. increment build number. missed doing +- it. +- Resolves: rhbz#1038183 remove BR for ant-nodeps. it's +- no long used. + +* Wed Jan 22 2014 David Knox - 0:7.0.42-2 +- Resolves: rhbz#1056673 Invocation of useradd with shell +- other than sbin nologin +- Resolves: rhbz#1056677 preun systemv scriptlet unconditionally +- stops service +- Resolves: rhbz#1056696 init.d tomcat does not conform to RHEL7 +- systemd rules. systemv subpackage is removed. +- Resolves: CVE-2013-4286 +- Resolves: CVE-2013-4322 +- Resolves: CVE-2014-0050 +- Built for rhel-7 RC + +* Tue Jan 21 2014 David Knox - 0:7.0.42-1 +- Resolves: rhbz#1051657 update to 7.0.42. Ant-nodeps is +- deprecated. + +* Fri Dec 27 2013 Daniel Mach - 07.0.40-3 +- Mass rebuild 2013-12-27 + * Sat May 11 2013 Ivan Afonichev 0:7.0.40-1 - Updated to 7.0.40 - Resolves: rhbz 956569 added missing commons-pool link