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]>

Reply via email to