CVE-2019-3563 (published 2019-04-29T16:29Z)

Wangle's LineBasedFrameDecoder contains logic for identifying newlines which incorrectly advances a buffer, leading to a potential underflow. This affects versions of Wangle prior to v2019.04.22.00

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-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/facebook/wangle
commit_details: repo_url: https://github.com/facebook/wangle
author: Kyle Nekritz
author_date: 2019-04-16 09:20:51-07:00
msg: Peek for \n in LineBasedFrameDecoder.

Summary:
Previously this could underflow if there was not a following \n.

CVE-2019-3563

Reviewed By: siyengar

Differential Revision: D14935715

fbshipit-source-id: 25c3eecf373f89efa1232456aeeb092f13b7fa06
repository: repo_url: https://github.com/facebook/wangle
repo_name: facebook/wangle
description: Wangle is a framework providing a set of common client/server abstractions for building services in a consistent, modular, and composable way.
repo_language: C++
owner: facebook
file_changes: filename: LineBasedFrameDecoder.cpp
change_type: ModificationType.MODIFY
diff: @@ -97,8 +97,9 @@ int64_t LineBasedFrameDecoder::findEndOfLine(IOBufQueue& buf) {
     auto b = c.read<char>();
     if (b == '\n' && terminatorType_ != TerminatorType::CARRIAGENEWLINE) {
       return i;
-    } else if (terminatorType_ != TerminatorType::NEWLINE &&
-               b == '\r' && !c.isAtEnd() && c.read<char>() == '\n') {
+    } else if (
+        terminatorType_ != TerminatorType::NEWLINE && b == '\r' &&
+        !c.isAtEnd() && *c.peekBytes().data() == '\n') {
       return i;
     }
   }

programming_language: C++
filename: CodecTest.cpp
change_type: ModificationType.MODIFY
diff: @@ -606,3 +606,37 @@ TEST(LineBasedFrameDecoder, CarriageNewLineOnly) {
   pipeline->read(q);
   EXPECT_EQ(called, 1);
 }
+
+TEST(LineBasedFrameDecoder, CarriageOnly) {
+  auto pipeline = Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>>::create();
+
+  (*pipeline)
+      .addBack(LineBasedFrameDecoder(
+          10, true, LineBasedFrameDecoder::TerminatorType::CARRIAGENEWLINE))
+      .addBack(test::FrameTester([&](std::unique_ptr<IOBuf>) { FAIL(); }))
+      .finalize();
+
+  IOBufQueue q(IOBufQueue::cacheChainLength());
+  q.append(IOBuf::copyBuffer("\raa"));
+  pipeline->read(q);
+}
+
+TEST(LineBasedFrameDecoder, DoubleCarriage) {
+  auto pipeline = Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>>::create();
+  int called = 0;
+
+  (*pipeline)
+      .addBack(LineBasedFrameDecoder(
+          10, true, LineBasedFrameDecoder::TerminatorType::CARRIAGENEWLINE))
+      .addBack(test::FrameTester([&](std::unique_ptr<IOBuf> buf) {
+        auto sz = buf->computeChainDataLength();
+        called++;
+        EXPECT_EQ(sz, 1);
+      }))
+      .finalize();
+
+  IOBufQueue q(IOBufQueue::cacheChainLength());
+  q.append(IOBuf::copyBuffer("\r\r\na\r\n"));
+  pipeline->read(q);
+  EXPECT_EQ(called, 2);
+}

programming_language: C++