/[packages]/updates/1/jetty/current/SOURCES/jetty-hashDOS.patch
ViewVC logotype

Contents of /updates/1/jetty/current/SOURCES/jetty-hashDOS.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 338274 - (show annotations) (download)
Thu Jan 3 17:06:17 2013 UTC (11 years, 3 months ago) by luigiwalser
File size: 16632 byte(s)
add patch to fix CVE-2011-4461
1 diff -up ./modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java.fix ./modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java
2 --- ./modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java.fix 2012-01-16 13:35:18.000000000 -0500
3 +++ ./modules/jetty/src/main/java/org/mortbay/jetty/handler/ContextHandler.java 2012-01-16 14:31:48.000000000 -0500
4 @@ -118,6 +118,7 @@ public class ContextHandler extends Hand
5 private Logger _logger;
6 private boolean _shutdown;
7 private boolean _allowNullPathInfo;
8 + private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",1000).intValue();
9 private int _maxFormContentSize=Integer.getInteger("org.mortbay.jetty.Request.maxFormContentSize",200000).intValue();
10 private boolean _compactPath=false;
11
12 @@ -1058,11 +1059,30 @@ public class ContextHandler extends Hand
13 }
14
15 /* ------------------------------------------------------------ */
16 + /**
17 + * Set the maximum size of a form post, to protect against DOS attacks from large forms.
18 + * @param maxSize
19 + */
20 public void setMaxFormContentSize(int maxSize)
21 {
22 _maxFormContentSize=maxSize;
23 }
24
25 + /* ------------------------------------------------------------ */
26 + public int getMaxFormKeys()
27 + {
28 + return _maxFormKeys;
29 + }
30 +
31 + /* ------------------------------------------------------------ */
32 + /**
33 + * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
34 + * @param max
35 + */
36 + public void setMaxFormKeys(int max)
37 + {
38 + _maxFormKeys = max;
39 + }
40
41 /* ------------------------------------------------------------ */
42 /**
43 diff -up ./modules/jetty/src/main/java/org/mortbay/jetty/Request.java.fix ./modules/jetty/src/main/java/org/mortbay/jetty/Request.java
44 --- ./modules/jetty/src/main/java/org/mortbay/jetty/Request.java.fix 2012-01-16 13:24:22.000000000 -0500
45 +++ ./modules/jetty/src/main/java/org/mortbay/jetty/Request.java 2012-01-16 13:32:38.000000000 -0500
46 @@ -98,6 +98,13 @@ import org.mortbay.util.ajax.Continuatio
47 * to avoid reparsing headers and cookies that are likely to be the same for
48 * requests from the same connection.
49 *
50 + * <p>
51 + * The form content that a request can process is limited to protect from Denial of Service
52 + * attacks. The size in bytes is limited by {@link ContextHandler#getMaxFormContentSize()} or if there is no
53 + * context then the "org.eclipse.jetty.server.Request.maxFormContentSize" {@link Server} attribute.
54 + * The number of parameters keys is limited by {@link ContextHandler#getMaxFormKeys()} or if there is no
55 + * context then the "org.eclipse.jetty.server.Request.maxFormKeys" {@link Server} attribute.
56 + *
57 * @author gregw
58 *
59 */
60 @@ -1546,16 +1553,23 @@ public class Request implements HttpServ
61 try
62 {
63 int maxFormContentSize=-1;
64 -
65 + int maxFormKeys=-1;
66 +
67 +
68 +
69 if (_context!=null)
70 + {
71 maxFormContentSize=_context.getContextHandler().getMaxFormContentSize();
72 + maxFormKeys=_context.getContextHandler().getMaxFormKeys();
73 + }
74 else
75 {
76 - Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.mortbay.jetty.Request.maxFormContentSize");
77 - if (size!=null)
78 - maxFormContentSize =size.intValue();
79 + Number size = (Number)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
80 + maxFormContentSize=size==null?200000:size.intValue();
81 + Number keys = (Number)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
82 + maxFormKeys =keys==null?1000:keys.intValue();
83 }
84 -
85 +
86 if (content_length>maxFormContentSize && maxFormContentSize > 0)
87 {
88 throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize);
89 @@ -1563,7 +1577,7 @@ public class Request implements HttpServ
90 InputStream in = getInputStream();
91
92 // Add form params to query params
93 - UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1);
94 + UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1,maxFormKeys);
95 }
96 catch (IOException e)
97 {
98 diff -up ./modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java.fix ./modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java
99 --- ./modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java.fix 2012-01-16 14:38:35.000000000 -0500
100 +++ ./modules/jetty/src/test/java/org/mortbay/jetty/RequestTest.java 2012-01-16 14:45:16.000000000 -0500
101 @@ -15,10 +15,13 @@
102
103 package org.mortbay.jetty;
104
105 -
106 +import java.io.BufferedReader;
107 +import java.io.File;
108 +import java.io.FileReader;
109 import java.io.IOException;
110 import java.io.Reader;
111 import java.util.ArrayList;
112 +import java.util.HashMap;
113
114 import javax.servlet.ServletException;
115 import javax.servlet.http.Cookie;
116 @@ -28,10 +31,14 @@ import javax.servlet.http.HttpServletRes
117 import junit.framework.TestCase;
118
119 import org.mortbay.jetty.Request;
120 +import org.eclipse.jetty.http.MimeTypes;
121 import org.mortbay.jetty.handler.AbstractHandler;
122 import org.mortbay.jetty.handler.HandlerCollection;
123 import org.mortbay.util.IO;
124 import org.mortbay.util.StringUtil;
125 +import org.eclipse.jetty.util.log.Log;
126 +
127 +
128
129 /**
130 * @author gregw
131 @@ -482,7 +489,52 @@ public class RequestTest extends TestCas
132 assertEquals("value7" ,cookie[7]);
133 }
134
135 -
136 + public void testHashDOS() throws Exception
137 + {
138 + _server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize",-1);
139 + _server.setAttribute("org.eclipse.jetty.server.Request.maxFormKeys",1000);
140 +
141 + // This file is not distributed - as it is dangerous
142 + File evil_keys = new File("/tmp/keys_mapping_to_zero_2m");
143 + if (!evil_keys.exists())
144 + {
145 + Log.info("testHashDOS skipped");
146 + return;
147 + }
148 +
149 + BufferedReader in = new BufferedReader(new FileReader(evil_keys));
150 + StringBuilder buf = new StringBuilder(4000000);
151 +
152 + String key=null;
153 + buf.append("a=b");
154 + while((key=in.readLine())!=null)
155 + {
156 + buf.append("&").append(key).append("=").append("x");
157 + }
158 + buf.append("&c=d");
159 +
160 + _handler._checker = new RequestTester()
161 + {
162 + public boolean check(HttpServletRequest request,HttpServletResponse response)
163 + {
164 + return "b".equals(request.getParameter("a")) && request.getParameter("c")==null;
165 + }
166 + };
167 +
168 + String request="POST / HTTP/1.1\r\n"+
169 + "Host: whatever\r\n"+
170 + "Content-Type: "+MimeTypes.FORM_ENCODED+"\r\n"+
171 + "Content-Length: "+buf.length()+"\r\n"+
172 + "Connection: close\r\n"+
173 + "\r\n"+
174 + buf;
175 +
176 + long start=System.currentTimeMillis();
177 + String response = _connector.getResponses(request);
178 + assertTrue(response.contains("200 OK"));
179 + long now=System.currentTimeMillis();
180 + assertTrue((now-start)<5000);
181 + }
182
183
184 interface RequestTester
185 @@ -498,8 +550,8 @@ public class RequestTest extends TestCas
186 public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException
187 {
188 ((Request)request).setHandled(true);
189 -
190 - if (request.getContentLength()>0)
191 +
192 + if (request.getContentLength()>0 && !MimeTypes.FORM_ENCODED.equals(request.getContentType()))
193 _content=IO.toString(request.getInputStream());
194
195 if (_checker!=null && _checker.check(request,response))
196 diff -up ./modules/util/src/main/java/org/mortbay/util/UrlEncoded.java.fix ./modules/util/src/main/java/org/mortbay/util/UrlEncoded.java
197 --- ./modules/util/src/main/java/org/mortbay/util/UrlEncoded.java.fix 2012-01-16 14:47:05.000000000 -0500
198 +++ ./modules/util/src/main/java/org/mortbay/util/UrlEncoded.java 2012-01-16 16:59:21.000000000 -0500
199 @@ -17,9 +17,11 @@ package org.mortbay.util;
200 import java.io.IOException;
201 import java.io.InputStream;
202 import java.io.InputStreamReader;
203 +import java.io.StringWriter;
204 import java.io.UnsupportedEncodingException;
205 import java.util.Iterator;
206 import java.util.Map;
207 +import org.mortbay.log.Log;
208
209
210 /* ------------------------------------------------------------ */
211 @@ -73,13 +75,13 @@ public class UrlEncoded extends MultiMap
212 /* ----------------------------------------------------------------- */
213 public void decode(String query)
214 {
215 - decodeTo(query,this,ENCODING);
216 + decodeTo(query,this,ENCODING,-1);
217 }
218
219 /* ----------------------------------------------------------------- */
220 public void decode(String query,String charset)
221 {
222 - decodeTo(query,this,charset);
223 + decodeTo(query,this,charset,-1);
224 }
225
226 /* -------------------------------------------------------------- */
227 @@ -174,6 +176,15 @@ public class UrlEncoded extends MultiMap
228 */
229 public static void decodeTo(String content, MultiMap map, String charset)
230 {
231 + decodeTo(content,map,charset,-1);
232 + }
233 +
234 + /* -------------------------------------------------------------- */
235 + /** Decoded parameters to Map.
236 + * @param content the string containing the encoded parameters
237 + */
238 + public static void decodeTo(String content, MultiMap map, String charset, int maxKeys)
239 + {
240 if (charset==null)
241 charset=ENCODING;
242
243 @@ -204,6 +215,11 @@ public class UrlEncoded extends MultiMap
244 }
245 key = null;
246 value=null;
247 + if (maxKeys>0 && map.size()>maxKeys)
248 + {
249 + Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys));
250 + return;
251 + }
252 break;
253 case '=':
254 if (key!=null)
255 @@ -320,9 +336,10 @@ public class UrlEncoded extends MultiMap
256 /** Decoded parameters to Map.
257 * @param in InputSteam to read
258 * @param map MultiMap to add parameters to
259 - * @param maxLength maximum length of content to read 0r -1 for no limit
260 + * @param maxLength maximum length of content to read or -1 for no limit
261 + * @param maxLength maximum number of keys to read or -1 for no limit
262 */
263 - public static void decode88591To(InputStream in, MultiMap map, int maxLength)
264 + public static void decode88591To(InputStream in, MultiMap map, int maxLength, int maxKeys)
265 throws IOException
266 {
267 synchronized(map)
268 @@ -352,6 +369,11 @@ public class UrlEncoded extends MultiMap
269 }
270 key = null;
271 value=null;
272 + if (maxKeys>0 && map.size()>maxKeys)
273 + {
274 + Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys));
275 + return;
276 + }
277 break;
278
279 case '=':
280 @@ -400,9 +422,10 @@ public class UrlEncoded extends MultiMap
281 /** Decoded parameters to Map.
282 * @param in InputSteam to read
283 * @param map MultiMap to add parameters to
284 - * @param maxLength maximum length of content to read 0r -1 for no limit
285 + * @param maxLength maximum length of content to read or -1 for no limit
286 + * @param maxLength maximum number of keys to read or -1 for no limit
287 */
288 - public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength)
289 + public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength, int maxKeys)
290 throws IOException
291 {
292 synchronized(map)
293 @@ -432,6 +455,11 @@ public class UrlEncoded extends MultiMap
294 }
295 key = null;
296 value=null;
297 + if (maxKeys>0 && map.size()>maxKeys)
298 + {
299 + Log.warn("maxFormKeys limit exceeded keys>{}",Integer.valueOf(maxKeys));
300 + return;
301 + }
302 break;
303
304 case '=':
305 @@ -477,43 +505,38 @@ public class UrlEncoded extends MultiMap
306 }
307
308 /* -------------------------------------------------------------- */
309 - public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength) throws IOException
310 + public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength, int maxKeys) throws IOException
311 {
312 InputStreamReader input = new InputStreamReader(in,StringUtil.__UTF16);
313 - StringBuffer buf = new StringBuffer();
314 -
315 - int c;
316 - int length=0;
317 - if (maxLength<0)
318 - maxLength=Integer.MAX_VALUE;
319 - while ((c=input.read())>0 && length++<maxLength)
320 - buf.append((char)c);
321 - decodeTo(buf.toString(),map,ENCODING);
322 + StringWriter buf = new StringWriter(8192);
323 + IO.copy(input,buf,maxLength);
324 +
325 + decodeTo(buf.getBuffer().toString(),map,ENCODING,maxKeys);
326 }
327
328 /* -------------------------------------------------------------- */
329 /** Decoded parameters to Map.
330 * @param in the stream containing the encoded parameters
331 */
332 - public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength)
333 + public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength, int maxKeys)
334 throws IOException
335 {
336
337 if (charset==null || StringUtil.__UTF8.equalsIgnoreCase(charset))
338 {
339 - decodeUtf8To(in,map,maxLength);
340 + decodeUtf8To(in,map,maxLength,maxKeys);
341 return;
342 }
343
344 if (StringUtil.__ISO_8859_1.equals(charset))
345 {
346 - decode88591To(in,map,maxLength);
347 + decode88591To(in,map,maxLength,maxKeys);
348 return;
349 }
350
351 if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings
352 {
353 - decodeUtf16To(in,map,maxLength);
354 + decodeUtf16To(in,map,maxLength,maxKeys);
355 return;
356 }
357
358 diff -up ./modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java.fix ./modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java
359 --- ./modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java.fix 2012-01-16 15:19:40.000000000 -0500
360 +++ ./modules/util/src/test/java/org/mortbay/util/URLEncodedTest.java 2012-01-16 15:20:36.000000000 -0500
361 @@ -163,7 +163,7 @@ public class URLEncodedTest extends juni
362 {
363 ByteArrayInputStream in = new ByteArrayInputStream("name\n=value+%30&name1=&name2&n\u00e3me3=value+3".getBytes(charsets[i][0]));
364 MultiMap m = new MultiMap();
365 - UrlEncoded.decodeTo(in, m, charsets[i][1], -1);
366 + UrlEncoded.decodeTo(in, m, charsets[i][1], -1, -1);
367 System.err.println(m);
368 assertEquals(i+" stream length",4,m.size());
369 assertEquals(i+" stream name\\n","value 0",m.getString("name\n"));
370 @@ -177,7 +177,7 @@ public class URLEncodedTest extends juni
371 {
372 ByteArrayInputStream in2 = new ByteArrayInputStream ("name=%83e%83X%83g".getBytes());
373 MultiMap m2 = new MultiMap();
374 - UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1);
375 + UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1, -1);
376 assertEquals("stream length",1,m2.size());
377 assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name"));
378 }

  ViewVC Help
Powered by ViewVC 1.1.30