DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10383>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10383 Specially crafted GET request causes the answering httpd process and the answering AJP13 processor to hang indefinitely Summary: Specially crafted GET request causes the answering httpd process and the answering AJP13 processor to hang indefinitely Product: Tomcat 4 Version: 4.0.4 Final Platform: PC OS/Version: Linux Status: NEW Severity: Major Priority: Other Component: Connector:JK/AJP (deprecated) AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] Hi, when using Apache, mod_jk 1.2.0 (the one delivered with Tomcat 4.0.4) and the AJP13 Connector of Tomcat 4.0.4, I encounter the problem, that a specially crafted GET request causes the answering httpd process and the answering AJP13 processor to hang indefinitely. I. Details on my enviroment: OS: Linux Webserver: Apache mod_jk: 1.2.0 (The one delivered with Tomcat 4.0.4) Tomcat: 4.0.4 JDK: 1.4.0_01-b03 Remark: This problem was also discovered with Tomcat 4.0.1 running on Solaris and JDK 1.3.1 II. How to reproduce the problem: 1. Setup a standard Apache, make mod_jk.so available to the modules directory of Apache (/usr/lib/apache in my case) and add the following configuration to your httpd.conf: LoadModule jk_module /usr/lib/apache/mod_jk.so AddModule mod_jk.c <IfModule mod_jk.c> Namevirtualhost 192.168.2.2:80 JkWorkersFile /etc/httpd/workers.properties JkLogFile /var/log/httpd/mod_jk.log JkLogLevel warn <VirtualHost 192.168.2.2:80> ServerName jktest.com DocumentRoot /tmp Transferlog /var/log/httpd/test.log JkMount /* ajp13 #JkMount /*.jsp ajp13 #JkMount /servlet/* ajp13 #JkMount /examples/* ajp13 </VirtualHost> </IfModule> 2. Use the following /etc/httpd/workers.properties: worker.list=ajp13 worker.ajp13.port=8009 worker.ajp13.host=localhost worker.ajp13.type=ajp13 worker.ajp13.lbfactor=1 3. Ensure that the AJP13 connector is configured the following way in server.xml: <Connector className="org.apache.ajp.tomcat4.Ajp13Connector" port="8009" minProcessors="5" maxProcessors="75" acceptCount="10" debug="1"/> 4. Start Tomcat and Apache. 5. Send the following request to the webserver (e.g. via telnet 192.168.2.2 80): GET / HTTP/1.0 Host: jktest.com Cookie: domain=blah III. What can be observed: 1. The telnet process does not return with any answer, but hangs indefinitely. 2. The anserwering httpd process is still connected to the telnet process Taking a look to the Apache server-status page says that this process is currently writing the response. 3. Doing a strace to the answering httpd process delivers the following: recv(10, (where 10 is the filedescriptor for the AJP13 TCP/IP connection) 4. The situation of the answering httpd process does not change, even when telnet is killed. The Apache server-status still says that this process is currently writing the response. 5. Tomcat throws the following exception to catalina_log.2002-07-01.txt: 2002-07-01 20:36:10 Ajp13Connector[8009] accepted socket, assigning to processor. 2002-07-01 20:36:10 Ajp13Connector[8009] about to create a processor, available=5, created=5, maxProcessors=75 2002-07-01 20:36:10 Ajp13Processor[8009][4] An incoming request is being assigned 2002-07-01 20:36:10 Ajp13Processor[8009][4] The incoming request has been awaited 2002-07-01 20:36:10 Ajp13Processor[8009][4] socket assigned. 2002-07-01 20:36:10 Ajp13Connector[8009] accepting socket... 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] setSocket() 2002-07-01 20:36:10 Ajp13Processor[8009][4] waiting on next request... 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] receiveNextRequest() 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] receive() 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] receive: total read = 89 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] Received 2 JK_AJP13_FORWARD_REQUEST 2002-07-01 20:36:10 Ajp13Processor[8009][4] [Ajp13] [RequestHandler] decodeRequest() 2002-07-01 20:36:10 Ajp13Processor[8009][4] received next request, status=200 2002-07-01 20:36:11 Ajp13Processor[8009][4] process: invoke java.lang.IllegalArgumentException: Cookie name domain is a reserved token at javax.servlet.http.Cookie.<init>(Cookie.java:185) at org.apache.ajp.tomcat4.Ajp13Request.addCookies(Ajp13Request.java:189) at org.apache.ajp.tomcat4.Ajp13Request.setAjpRequest(Ajp13Request.java:148) at org.apache.ajp.tomcat4.Ajp13Processor.process(Ajp13Processor.java:446) at org.apache.ajp.tomcat4.Ajp13Processor.run(Ajp13Processor.java:551) at java.lang.Thread.run(Thread.java:536) 2002-07-01 20:36:11 Ajp13Processor[8009][4] recyling objects ... 2002-07-01 20:36:11 Ajp13Processor[8009][4] [Ajp13] recycle() 2002-07-01 20:36:11 Ajp13Processor[8009][4] waiting on next request... 2002-07-01 20:36:11 Ajp13Processor[8009][4] [Ajp13] receiveNextRequest() 2002-07-01 20:36:11 Ajp13Processor[8009][4] [Ajp13] receive() IV. Conclusion If the request shown in II.5 is executed often enough all httpd processes will be blocked. Furthermore if there are more possible httpd processes than Tomcat processors Tomcat (MaxClients > maxProcessors) will have no processors left to answer requests. This can be used for a denial of service attack on Apache/Tomcat connected via AJP13. V. Discussion of the problem >From my point of view the main source of the problem can be found in Ajp13Processor.java in lines 441 till 473: try { // set flag handlingRequest.set(true); // set up request request.setAjpRequest(ajpRequest); request.setResponse(response); request.setStream(input); // setup response response.setRequest(request); response.setStream(output); if (debug > 0) { logger.log("invoking..."); } connector.getContainer().invoke(request, response); if (debug > 0) { logger.log("done invoking, finishing request/response...."); } response.finishResponse(); request.finishRequest(); if (debug > 0) { logger.log("finished handling request."); } } catch (Throwable e) { logger.log("process: invoke", e); } Although every exeception produced during the processing of the request will be caught, no care will be taken to ensure that there is a definitive response back to the waiting httpd process (it is waiting for an answer indefinitely as seen by staying in the recv syscall). >From my point of view the catch clause should contain code that sends a code 500 together with a stack trace back to Apache. If it is impossible to do so (maybe because no response object could be setup correctly) at least the while loop should be left. >From my point of view this blocking situation can be caused by many more exceptions that are caught by the catch clause in line 471, not only by the IllegalArgumentException caused by the wrong cookie in my request. Regards Rüdiger Plüm -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>