CVE-2018-6337 (published 2018-12-31T22:29Z)

folly::secureRandom will re-use a buffer between parent and child processes when fork() is called. That will result in multiple forked children producing repeat (or similar) results. This affects HHVM 3.26 prior to 3.26.3 and the folly library between v2017.12.11.00 and v2018.08.09.00.

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

Weakness information:
cwe_id: CWE-119
cwe_name: Improper Restriction of Operations within the Bounds of a Memory Buffer
description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
extended_description: 
            Certain languages allow direct addressing of memory locations and do not automatically ensure that these locations are valid for the memory buffer that is being referenced. This can cause read or write operations to be performed on memory locations that may be associated with other variables, data structures, or internal program data.
         
         

Fix information:
repo_url: https://github.com/facebook/folly
commit_details: repo_url: https://github.com/facebook/folly
author: Fred Emmott
author_date: 2018-08-08 16:53:47-07:00
msg: Flush secureRandom buffer on fork

Summary: On fork, flush the secureRandom buffer, so that we don't share entropy between the parent and child.

Reviewed By: ricklavoie

Differential Revision: D9196474

fbshipit-source-id: 12ff8488d814466186df61328a5f1d4000beb27f
repository: repo_url: https://github.com/facebook/folly
repo_name: facebook/folly
description: An open-source C++ library developed and used at Facebook.
repo_language: C++
owner: facebook
file_changes: filename: Random.cpp
change_type: ModificationType.MODIFY
diff: @@ -72,6 +72,7 @@ void readRandomDevice(void* data, size_t size) {
 
 class BufferedRandomDevice {
  public:
+  static once_flag flag;
   static constexpr size_t kDefaultBufferSize = 128;
 
   explicit BufferedRandomDevice(size_t bufferSize = kDefaultBufferSize);
@@ -97,10 +98,28 @@ class BufferedRandomDevice {
   unsigned char* ptr_;
 };
 
+once_flag BufferedRandomDevice::flag;
+struct RandomTag {};
+
 BufferedRandomDevice::BufferedRandomDevice(size_t bufferSize)
   : bufferSize_(bufferSize),
     buffer_(new unsigned char[bufferSize]),
     ptr_(buffer_.get() + bufferSize) {  // refill on first use
+  call_once(flag, [this]() {
+    detail::AtFork::registerHandler(
+        this,
+        /*prepare*/ []() { return true; },
+        /*parent*/ []() {},
+        /*child*/
+        []() {
+          using Single = SingletonThreadLocal<BufferedRandomDevice, RandomTag>;
+          auto& t = Single::get();
+          // Clear out buffered data on fork.
+          //
+          // Ensure child and parent do not share same entropy pool.
+          t.ptr_ = t.buffer_.get() + t.bufferSize_;
+        });
+  });
 }
 
 void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
@@ -124,8 +143,6 @@ void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
   ptr_ += size;
 }
 
-struct RandomTag {};
-
 } // namespace
 
 void Random::secureRandom(void* data, size_t size) {

programming_language: C++
filename: RandomTest.cpp
change_type: ModificationType.MODIFY
diff: @@ -138,3 +138,24 @@ TEST(Random, sanity) {
         std::unordered_set<uint64_t>(vals.begin(), vals.end()).size());
   }
 }
+
+TEST(Random, SecureFork) {
+  unsigned char buffer = 0;
+  // Init random buffer
+  folly::Random::secureRandom(&buffer, 1);
+
+  auto pid = fork();
+  EXPECT_NE(pid, -1);
+  if (pid) {
+    // parent
+    int status = 0;
+    folly::Random::secureRandom(&buffer, 1);
+    auto pid2 = wait(&status);
+    EXPECT_NE(WEXITSTATUS(status), buffer);
+    EXPECT_EQ(pid, pid2);
+  } else {
+    // child
+    folly::Random::secureRandom(&buffer, 1);
+    exit(buffer); // Do not print gtest results
+  }
+}

programming_language: C++