https://bz.apache.org/bugzilla/show_bug.cgi?id=69814

            Bug ID: 69814
           Summary: HttpSession.isNew() may return true on an existing
                    session due to a race condition
           Product: Tomcat 10
           Version: 10.1.44
          Hardware: PC
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: csa...@gmail.com
  Target Milestone: ------

In a stateful application where HttpSession is used, session.isNew() should
return true in the request where the session is just created anew; and false
when it is retrieved from an existing one. However, very infrequently, it could
return TRUE under some particular execution sequence as follows:

1) Client sends the 1st request
2) Server receives the 1st request and processes it in thread T1. Session S is
created. Its "isnew" field is set to true. Response is flushed. T1 is paused
(e.g. due to context switching) before calling StandardSession.endAccess().
3) Client receives the response, including the JSESSIONID
4) Client sends the 2nd request with the JSESSIONID
5) Server receives the 2nd request and processes it in thread T2.
StandardManager finds the session S using the given JSESSIONID successfully.
The application calls session.isNew() which unexpectedly returns TRUE. Response
is then returned to client
6) Server's thread T1 continues to run StandardSession.endAccess() after
outputting the response, which set the session S's isnew field to false:
https://github.com/apache/tomcat/blob/10.1.45/java/org/apache/catalina/session/StandardSession.java#L535
(also see the attached thread dump 1st_request_thread_dump.txt)
7) In subsequent requests, isnew() returns false as expected.

Normally, session.isNew() is false if 6) occurs before 5), but when the server
is slow or client is too fast, the above sequence will trigger the bug. I could
easily reproduce it on Linux and Windows with the help of a debugger to enforce
such a sequence.


How to reproduce:
Set a breakpoint to pause at StandardSession.endAccess() and fire two requests
successively.

1) Deploy the attached demo application (attached TomcatApp.war):
set JAVA_OPTS in startup.sh/.bat script to enable remote debugging:
JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,address=*:9999,server=y,suspend=n"
override the conf/server.xml with the attached that sets the listening port to
9080 and disables TLS redirection.

2) Open the demo project (attached TomcatHello.zip) in IntelliJ IDEA
3) Set breakpoint at StandardSession.endAccess()
4) Set remote JVM debug to localhost:9999
5) Open a console
6) Run the following in sequence:
curl -c cookies.txt http://localhost:9080/TomcatApp/hello
(breakpoint hit)
(output: Session isNew? true)
curl -b cookies.txt http://localhost:9080/TomcatApp/hello
(output: Session isNew? true)
(Detach the debugger)
curl -b cookies.txt http://localhost:9080/TomcatApp/hello
(output: Session isNew? false)

(See also the attached video demo.mp4)

Regards,
Sammy Chan

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to