CVE-2018-12584 (published 2018-07-16T20:29Z)

The ConnectionBase::preparseNewBytes function in resip/stack/ConnectionBase.cxx in reSIProcate through 1.10.2 allows remote attackers to cause a denial of service (buffer overflow) or possibly execute arbitrary code when TLS communication is enabled.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-120
cwe_name: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
extended_description: A buffer overflow condition exists when a product attempts to put more data in a buffer than it can hold, or when it attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the product copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
         

Fix information:
repo_url: https://github.com/resiprocate/resiprocate
commit_details: repo_url: https://github.com/resiprocate/resiprocate
author: Scott Godin
author_date: 2018-06-21 10:24:38-04:00
msg: -fixed an issue where the stack could crash if a TCP based sender sends a Content-Length that is less that the actual SIP body transmitted
 in order to trigger this condition the SIP message body must arrive in a separate read request, either from the start or part way through the body
 and there must be data following the body in the same read.
repository: repo_url: https://github.com/resiprocate/resiprocate
repo_name: resiprocate/resiprocate
description: C++ implementation of SIP, ICE, TURN and related protocols.
repo_language: C++
owner: resiprocate
file_changes: filename: ConnectionBase.cxx
change_type: ModificationType.MODIFY
diff: @@ -397,7 +397,7 @@ ConnectionBase::preparseNewBytes(int bytesRead)
                   mBufferSize = size;
                   
                   DebugLog (<< "Extra bytes after message: " << overHang);
-                  DebugLog (<< Data(mBuffer, overHang));
+                  //DebugLog (<< Data(mBuffer, overHang));
                   
                   bytesRead = overHang;
                }
@@ -471,11 +471,36 @@ ConnectionBase::preparseNewBytes(int bytesRead)
          }
 
          mBufferPos += bytesRead;
-         if (mBufferPos == contentLength)
+         if (mBufferPos >= contentLength)
          {
+            int overHang = mBufferPos - (int)contentLength;
+            char *overHangStart = mBuffer + contentLength;
+
             mMessage->addBuffer(mBuffer);
             mMessage->setBody(mBuffer, (UInt32)contentLength);
-            mBuffer=0;
+            mConnState = NewMessage;
+            mBuffer = 0;
+
+            if (overHang > 0)
+            {
+                // The next message has been partially read.
+                size_t size = overHang * 3 / 2;
+                if (size < ConnectionBase::ChunkSize)
+                {
+                    size = ConnectionBase::ChunkSize;
+                }
+                char* newBuffer = MsgHeaderScanner::allocateBuffer((int)size);
+                memcpy(newBuffer, overHangStart, overHang);
+                mBuffer = newBuffer;
+                mBufferPos = 0;
+                mBufferSize = size;
+
+                DebugLog(<< "Extra bytes after message: " << overHang);
+                //DebugLog(<< Data(mBuffer, overHang));
+
+                bytesRead = overHang;
+            }
+
             // .bwc. basicCheck takes up substantial CPU. Don't bother doing it
             // if we're overloaded.
             CongestionManager::RejectionBehavior b=mTransport->getRejectionBehaviorForIncoming();
@@ -515,11 +540,16 @@ ConnectionBase::preparseNewBytes(int bytesRead)
                mTransport->pushRxMsgUp(mMessage);
                mMessage = 0;
             }
-            mConnState = NewMessage;
+            
+            if (overHang > 0) 
+            {
+               goto start;
+            }
          }
          else if (mBufferPos == mBufferSize)
          {
-            // .bwc. We've filled our buffer; go ahead and make more room.
+            // .bwc. We've filled our buffer and haven't read contentLength bytes yet; go ahead and make more room.
+            assert(contentLength >= mBufferSize);
             size_t newSize = resipMin(mBufferSize*3/2, contentLength);
             char* newBuffer = 0;
             try

programming_language: C++