Author: nthykier Date: 2012-04-25 10:01:33 +0000 (Wed, 25 Apr 2012) New Revision: 16000
Added: trunk/jetty/debian/patches/CVE-2011-4461.patch Modified: trunk/jetty/debian/changelog trunk/jetty/debian/patches/series Log: Apply fix for CVE-2011-4461 Modified: trunk/jetty/debian/changelog =================================================================== --- trunk/jetty/debian/changelog 2012-04-25 09:57:30 UTC (rev 15999) +++ trunk/jetty/debian/changelog 2012-04-25 10:01:33 UTC (rev 16000) @@ -7,11 +7,13 @@ * Updated d/copyright to DEP-5 format 1.0. * Exit 0 in jetty's init script if jetty is already running. Thanks to Toby for the report and patch. (Closes: #626382) - * Fix mispelled "character-class" in grep invocation. Thanks + * Fix misspelled "character-class" in grep invocation. Thanks to Isaac for the report and correction. (Closes: #637961) * Allow java.library.path to be set in /etc/default/jetty. Thanks to "biddster" for the report and the patches. (Closes: #600175, LP: #656374) + * Apply patch from Fedora to fix hash collision related DOS. + - CVE-2011-4461 -- Niels Thykier <ni...@thykier.net> Wed, 25 Apr 2012 11:06:04 +0200 Added: trunk/jetty/debian/patches/CVE-2011-4461.patch =================================================================== --- trunk/jetty/debian/patches/CVE-2011-4461.patch (rev 0) +++ trunk/jetty/debian/patches/CVE-2011-4461.patch 2012-04-25 10:01:33 UTC (rev 16000) @@ -0,0 +1,376 @@ +Description: Fix for Hash collision, see CVE-2011-4461 +Origin: https://bugzilla.redhat.com/attachment.cgi?id=556318&action=diff + +--- a/modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java 2012-01-16 13:35:18.000000000 -0500 ++++ b/modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java 2012-01-16 14:31:48.000000000 -0500 +@@ -118,6 +118,7 @@ public class ContextHandler extends Hand + private Logger _logger; + private boolean _shutdown; + private boolean _allowNullPathInfo; ++ private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",1000).intValue(); + private int _maxFormContentSize=Integer.getInteger("org.mortbay.jetty.Request.maxFormContentSize",200000).intValue(); + private boolean _compactPath=false; + +@@ -1058,11 +1059,30 @@ public class ContextHandler extends Hand + } + + /* ------------------------------------------------------------ */ ++ /** ++ * Set the maximum size of a form post, to protect against DOS attacks from large forms. ++ * @param maxSize ++ */ + public void setMaxFormContentSize(int maxSize) + { + _maxFormContentSize=maxSize; + } + ++ /* ------------------------------------------------------------ */ ++ public int getMaxFormKeys() ++ { ++ return _maxFormKeys; ++ } ++ ++ /* ------------------------------------------------------------ */ ++ /** ++ * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys. ++ * @param max ++ */ ++ public void setMaxFormKeys(int max) ++ { ++ _maxFormKeys = max; ++ } + + /* ------------------------------------------------------------ */ + /** +--- a/modules/jetty/src/main/java/org/mortbay/jetty/Request.java 2012-01-16 13:24:22.000000000 -0500 ++++ b/modules/jetty/src/main/java/org/mortbay/jetty/Request.java 2012-01-16 13:32:38.000000000 -0500 +@@ -98,6 +98,13 @@ import org.mortbay.util.ajax.Continuatio + * to avoid reparsing headers and cookies that are likely to be the same for + * requests from the same connection. + * ++ * <p> ++ * The form content that a request can process is limited to protect from Denial of Service ++ * attacks. The size in bytes is limited by {@link ContextHandler#getMaxFormContentSize()} or if there is no ++ * context then the "org.eclipse.jetty.server.Request.maxFormContentSize" {@link Server} attribute. ++ * The number of parameters keys is limited by {@link ContextHandler#getMaxFormKeys()} or if there is no ++ * context then the "org.eclipse.jetty.server.Request.maxFormKeys" {@link Server} attribute. ++ * + * @author gregw + * + */ +@@ -1546,16 +1553,23 @@ public class Request implements HttpServ + try + { + int maxFormContentSize=-1; +- ++ int maxFormKeys=-1; ++ ++ ++ + if (_context!=null) ++ { + maxFormContentSize=_context.getContextHandler().getMaxFormContentSize(); ++ maxFormKeys=_context.getContextHandler().getMaxFormKeys(); ++ } + else + { +- Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.mortbay.jetty.Request.maxFormContentSize"); +- if (size!=null) +- maxFormContentSize =size.intValue(); ++ Number size = (Number)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize"); ++ maxFormContentSize=size==null?200000:size.intValue(); ++ Number keys = (Number)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys"); ++ maxFormKeys =keys==null?1000:keys.intValue(); + } +- ++ + if (content_length>maxFormContentSize && maxFormContentSize > 0) + { + throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize); +@@ -1563,7 +1577,7 @@ public class Request implements HttpServ + InputStream in = getInputStream(); + + // Add form params to query params +- UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1); ++ UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1,maxFormKeys); + } + catch (IOException e) + { +--- a/modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java 2012-01-16 14:38:35.000000000 -0500 ++++ b/modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java 2012-01-16 14:45:16.000000000 -0500 +@@ -15,10 +15,13 @@ + + package org.mortbay.jetty; + +- ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; + import java.io.IOException; + import java.io.Reader; + import java.util.ArrayList; ++import java.util.HashMap; + + import javax.servlet.ServletException; + import javax.servlet.http.Cookie; +@@ -28,10 +31,14 @@ import javax.servlet.http.HttpServletRes + import junit.framework.TestCase; + + import org.mortbay.jetty.Request; ++import org.mortbay.jetty.MimeTypes; + import org.mortbay.jetty.handler.AbstractHandler; + import org.mortbay.jetty.handler.HandlerCollection; + import org.mortbay.util.IO; + import org.mortbay.util.StringUtil; ++import org.mortbay.log.Log; ++ ++ + + /** + * @author gregw +@@ -482,7 +489,52 @@ public class RequestTest extends TestCas + assertEquals("value7" ,cookie[7]); + } + +- ++ public void testHashDOS() throws Exception ++ { ++ _server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize",-1); ++ _server.setAttribute("org.eclipse.jetty.server.Request.maxFormKeys",1000); ++ ++ // This file is not distributed - as it is dangerous ++ File evil_keys = new File("/tmp/keys_mapping_to_zero_2m"); ++ if (!evil_keys.exists()) ++ { ++ Log.info("testHashDOS skipped"); ++ return; ++ } ++ ++ BufferedReader in = new BufferedReader(new FileReader(evil_keys)); ++ StringBuilder buf = new StringBuilder(4000000); ++ ++ String key=null; ++ buf.append("a=b"); ++ while((key=in.readLine())!=null) ++ { ++ buf.append("&").append(key).append("=").append("x"); ++ } ++ buf.append("&c=d"); ++ ++ _handler._checker = new RequestTester() ++ { ++ public boolean check(HttpServletRequest request,HttpServletResponse response) ++ { ++ return "b".equals(request.getParameter("a")) && request.getParameter("c")==null; ++ } ++ }; ++ ++ String request="POST / HTTP/1.1\r\n"+ ++ "Host: whatever\r\n"+ ++ "Content-Type: "+MimeTypes.FORM_ENCODED+"\r\n"+ ++ "Content-Length: "+buf.length()+"\r\n"+ ++ "Connection: close\r\n"+ ++ "\r\n"+ ++ buf; ++ ++ long start=System.currentTimeMillis(); ++ String response = _connector.getResponses(request); ++ assertTrue(response.contains("200 OK")); ++ long now=System.currentTimeMillis(); ++ assertTrue((now-start)<5000); ++ } + + + interface RequestTester +@@ -498,8 +550,8 @@ public class RequestTest extends TestCas + public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException + { + ((Request)request).setHandled(true); +- +- if (request.getContentLength()>0) ++ ++ if (request.getContentLength()>0 && !MimeTypes.FORM_ENCODED.equals(request.getContentType())) + _content=IO.toString(request.getInputStream()); + + if (_checker!=null && _checker.check(request,response)) +--- a/modules/util/src/main/java/org/mortbay/util/UrlEncoded.java 2012-01-16 14:47:05.000000000 -0500 ++++ b/modules/util/src/main/java/org/mortbay/util/UrlEncoded.java 2012-01-16 16:59:21.000000000 -0500 +@@ -17,9 +17,11 @@ package org.mortbay.util; + import java.io.IOException; + import java.io.InputStream; + import java.io.InputStreamReader; ++import java.io.StringWriter; + import java.io.UnsupportedEncodingException; + import java.util.Iterator; + import java.util.Map; ++import org.mortbay.log.Log; + + + /* ------------------------------------------------------------ */ +@@ -73,13 +75,13 @@ public class UrlEncoded extends MultiMap + /* ----------------------------------------------------------------- */ + public void decode(String query) + { +- decodeTo(query,this,ENCODING); ++ decodeTo(query,this,ENCODING,-1); + } + + /* ----------------------------------------------------------------- */ + public void decode(String query,String charset) + { +- decodeTo(query,this,charset); ++ decodeTo(query,this,charset,-1); + } + + /* -------------------------------------------------------------- */ +@@ -174,6 +176,15 @@ public class UrlEncoded extends MultiMap + */ + public static void decodeTo(String content, MultiMap map, String charset) + { ++ decodeTo(content,map,charset,-1); ++ } ++ ++ /* -------------------------------------------------------------- */ ++ /** Decoded parameters to Map. ++ * @param content the string containing the encoded parameters ++ */ ++ public static void decodeTo(String content, MultiMap map, String charset, int maxKeys) ++ { + if (charset==null) + charset=ENCODING; + +@@ -204,6 +215,11 @@ public class UrlEncoded extends MultiMap + } + key = null; + value=null; ++ if (maxKeys>0 && map.size()>maxKeys) ++ { ++ Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys)); ++ return; ++ } + break; + case '=': + if (key!=null) +@@ -320,9 +336,10 @@ public class UrlEncoded extends MultiMap + /** Decoded parameters to Map. + * @param in InputSteam to read + * @param map MultiMap to add parameters to +- * @param maxLength maximum length of content to read 0r -1 for no limit ++ * @param maxLength maximum length of content to read or -1 for no limit ++ * @param maxLength maximum number of keys to read or -1 for no limit + */ +- public static void decode88591To(InputStream in, MultiMap map, int maxLength) ++ public static void decode88591To(InputStream in, MultiMap map, int maxLength, int maxKeys) + throws IOException + { + synchronized(map) +@@ -352,6 +369,11 @@ public class UrlEncoded extends MultiMap + } + key = null; + value=null; ++ if (maxKeys>0 && map.size()>maxKeys) ++ { ++ Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys)); ++ return; ++ } + break; + + case '=': +@@ -400,9 +422,10 @@ public class UrlEncoded extends MultiMap + /** Decoded parameters to Map. + * @param in InputSteam to read + * @param map MultiMap to add parameters to +- * @param maxLength maximum length of content to read 0r -1 for no limit ++ * @param maxLength maximum length of content to read or -1 for no limit ++ * @param maxLength maximum number of keys to read or -1 for no limit + */ +- public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength) ++ public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength, int maxKeys) + throws IOException + { + synchronized(map) +@@ -432,6 +455,11 @@ public class UrlEncoded extends MultiMap + } + key = null; + value=null; ++ if (maxKeys>0 && map.size()>maxKeys) ++ { ++ Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys)); ++ return; ++ } + break; + + case '=': +@@ -477,43 +505,38 @@ public class UrlEncoded extends MultiMap + } + + /* -------------------------------------------------------------- */ +- public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength) throws IOException ++ public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength, int maxKeys) throws IOException + { + InputStreamReader input = new InputStreamReader(in,StringUtil.__UTF16); +- StringBuffer buf = new StringBuffer(); +- +- int c; +- int length=0; +- if (maxLength<0) +- maxLength=Integer.MAX_VALUE; +- while ((c=input.read())>0 && length++<maxLength) +- buf.append((char)c); +- decodeTo(buf.toString(),map,ENCODING); ++ StringWriter buf = new StringWriter(8192); ++ IO.copy(input,buf,maxLength); ++ ++ decodeTo(buf.getBuffer().toString(),map,ENCODING,maxKeys); + } + + /* -------------------------------------------------------------- */ + /** Decoded parameters to Map. + * @param in the stream containing the encoded parameters + */ +- public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength) ++ public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength, int maxKeys) + throws IOException + { + + if (charset==null || StringUtil.__UTF8.equalsIgnoreCase(charset)) + { +- decodeUtf8To(in,map,maxLength); ++ decodeUtf8To(in,map,maxLength,maxKeys); + return; + } + + if (StringUtil.__ISO_8859_1.equals(charset)) + { +- decode88591To(in,map,maxLength); ++ decode88591To(in,map,maxLength,maxKeys); + return; + } + + if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings + { +- decodeUtf16To(in,map,maxLength); ++ decodeUtf16To(in,map,maxLength,maxKeys); + return; + } + +--- a/modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java 2012-01-16 15:19:40.000000000 -0500 ++++ b/modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java 2012-01-16 15:20:36.000000000 -0500 +@@ -163,7 +163,7 @@ public class URLEncodedTest extends juni + { + ByteArrayInputStream in = new ByteArrayInputStream("name\n=value+%30&name1=&name2&n\u00e3me3=value+3".getBytes(charsets[i][0])); + MultiMap m = new MultiMap(); +- UrlEncoded.decodeTo(in, m, charsets[i][1], -1); ++ UrlEncoded.decodeTo(in, m, charsets[i][1], -1, -1); + System.err.println(m); + assertEquals(i+" stream length",4,m.size()); + assertEquals(i+" stream name\\n","value 0",m.getString("name\n")); +@@ -177,7 +177,7 @@ public class URLEncodedTest extends juni + { + ByteArrayInputStream in2 = new ByteArrayInputStream ("name=%83e%83X%83g".getBytes()); + MultiMap m2 = new MultiMap(); +- UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1); ++ UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1, -1); + assertEquals("stream length",1,m2.size()); + assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name")); + } Modified: trunk/jetty/debian/patches/series =================================================================== --- trunk/jetty/debian/patches/series 2012-04-25 09:57:30 UTC (rev 15999) +++ trunk/jetty/debian/patches/series 2012-04-25 10:01:33 UTC (rev 16000) @@ -1 +1,2 @@ 01_add_manifests_with_osgi_bundles_info.patch +CVE-2011-4461.patch _______________________________________________ pkg-java-commits mailing list pkg-java-comm...@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits