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

            Bug ID: 61998
           Summary: tomcat: dead loop in the processing of SSL handshake
           Product: Tomcat 8
           Version: 8.5.15
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: critical
          Priority: P2
         Component: Util
          Assignee: dev@tomcat.apache.org
          Reporter: mycatc...@163.com
  Target Milestone: ----

During our https attack test, a dead loop has happened in
org.apache.tomcat.util.net.SecureNioChannel#handshake.

A lot of(million) packets were sent during the test so it's extremely hard to
find which one caused the problem.
The dead loop didn't stop even after we had stopped the test.

I've debugged tomcat using jdb. The results are as follows.

while (!handshakeComplete) {
    switch ( handshakeStatus ) {                                               
            //handshakeStatus = NEED_UNWRAP
        //...
        case NEED_UNWRAP: {
            //perform the unwrap function
            handshake = handshakeUnwrap(read);                                 
           //handshake.getStatus() = Status.BUFFER_OVERFLOW
            if ( handshake.getStatus() == Status.OK ) {
                if (handshakeStatus == HandshakeStatus.NEED_TASK)
                    handshakeStatus = tasks();
            } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
                //read more data, reregister for OP_READ
                return SelectionKey.OP_READ;
            } else if (handshake.getStatus() == Status.BUFFER_OVERFLOW) {
                getBufHandler().configureReadBufferForWrite();
            } else {
                throw new
IOException(sm.getString("channel.nio.ssl.unexpectedStatusDuringWrap",
handshakeStatus));
            }//switch
            break;
        }
        case NEED_TASK: {
            handshakeStatus = tasks();
            break;
        }
        default: throw new
IllegalStateException(sm.getString("channel.nio.ssl.invalidStatus",
handshakeStatus));
    }
}

protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {

    if (netInBuffer.position() == netInBuffer.limit()) {
        //clear the buffer if we have emptied it out on data
        netInBuffer.clear();
    }

/**
Value of netInBuffer here.

https-jsse-nio-20000-exec-38[1] dump netInBuffer
 netInBuffer = {
    java.nio.ByteBuffer.hb: instance of byte[16921] (id=9332)
    java.nio.ByteBuffer.offset: 0
    java.nio.ByteBuffer.isReadOnly: false
    java.nio.ByteBuffer.bigEndian: true
    java.nio.ByteBuffer.nativeByteOrder: false
    java.nio.Buffer.SPLITERATOR_CHARACTERISTICS: 16464
    java.nio.Buffer.mark: -1
    java.nio.Buffer.position: 16
    java.nio.Buffer.limit: 16921
    java.nio.Buffer.capacity: 16921
    java.nio.Buffer.address: 0
}
*
/
    if ( doread )  {
        //if we have data to read, read it
        int read = sc.read(netInBuffer);                                       
                        //read = 0
        if (read == -1) throw new
IOException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
    }
    SSLEngineResult result;
    boolean cont = false;
    //loop while we can perform pure SSLEngine data
    do {
        //prepare the buffer with the incoming data
        netInBuffer.flip();
        //call unwrap
        getBufHandler().configureReadBufferForWrite();
        result = sslEngine.unwrap(netInBuffer,
getBufHandler().getReadBuffer());                    //result: "Status =
BUFFER_OVERFLOW HandshakeStatus = NEED_UNWRAP bytesConsumed = 0 bytesProduced =
0"
        //compact the buffer, this is an optional method, wonder what would
happen if we didn't
        netInBuffer.compact();
        //read in the status
        handshakeStatus = result.getHandshakeStatus();
        if ( result.getStatus() == SSLEngineResult.Status.OK &&
             result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
            //execute tasks if we need to
            handshakeStatus = tasks();
        }
        //perform another unwrap?
        cont = result.getStatus() == SSLEngineResult.Status.OK &&
               handshakeStatus == HandshakeStatus.NEED_UNWRAP;
    }while ( cont );
    return result;
}

Since sc.read(netInBuffer) returns 0, I'm wondering configuring timeout,
keepalive or something else to avoid the problem.

I'd appreciated if you can confirm if there is a bug or have any suggestions to
avoid the problem.

Thanks a lot.

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