Fix one-second spin in fx_random.cpp

Take seed generation logic from base's address_space_randomization.cc.
One small tweak is to avoid the bottom three bits of a stack address and
invert, to make leaking ASLR more difficult along the lines of the
freelist masking in base's partition allocator. Another tweak is to
mix in some more time-based information. Another tweak is to add in
the times called so that rapid successive calls return different results.

Bug: pdfium:891
Change-Id: I14238da15cee9c8d4ca72d79e4f7fbb26997c619
Reviewed-on: https://pdfium-review.googlesource.com/13490
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index deaa706..ca4c9ee 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1932,6 +1932,7 @@
     "core/fxcrt/fx_coordinates_unittest.cpp",
     "core/fxcrt/fx_extension_unittest.cpp",
     "core/fxcrt/fx_memory_unittest.cpp",
+    "core/fxcrt/fx_random_unittest.cpp",
     "core/fxcrt/fx_string_unittest.cpp",
     "core/fxcrt/fx_system_unittest.cpp",
     "core/fxge/dib/cstretchengine_unittest.cpp",
diff --git a/core/fxcrt/fx_random.cpp b/core/fxcrt/fx_random.cpp
index 866a7a9..483a56b 100644
--- a/core/fxcrt/fx_random.cpp
+++ b/core/fxcrt/fx_random.cpp
@@ -19,86 +19,85 @@
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
 #include <wincrypt.h>
 #else  // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
-#include <ctime>
+#include <sys/time.h>
+#include <unistd.h>
 #endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
 
 namespace {
 
 struct MTContext {
-  MTContext() {
-    mti = MT_N + 1;
-    bHaveSeed = false;
-  }
-
   uint32_t mti;
-  bool bHaveSeed;
   uint32_t mt[MT_N];
 };
 
+bool g_bHaveGlobalSeed = false;
+uint32_t g_nGlobalSeed = 0;
+
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
-bool GenerateCryptoRandom(uint32_t* pBuffer, int32_t iCount) {
+bool GenerateSeedFromCryptoRandom(uint32_t* pSeed) {
   HCRYPTPROV hCP = 0;
   if (!::CryptAcquireContext(&hCP, nullptr, nullptr, PROV_RSA_FULL, 0) ||
       !hCP) {
     return false;
   }
-  ::CryptGenRandom(hCP, iCount * sizeof(uint32_t),
-                   reinterpret_cast<uint8_t*>(pBuffer));
+  ::CryptGenRandom(hCP, sizeof(uint32_t), reinterpret_cast<uint8_t*>(pSeed));
   ::CryptReleaseContext(hCP, 0);
   return true;
 }
 #endif
 
-void Random_GenerateBase(uint32_t* pBuffer, int32_t iCount) {
+uint32_t GenerateSeedFromEnvironment() {
+  char c;
+  uintptr_t p = reinterpret_cast<uintptr_t>(&c);
+  uint32_t seed = ~static_cast<uint32_t>(p >> 3);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
-  SYSTEMTIME st1, st2;
-  ::GetSystemTime(&st1);
-  do {
-    ::GetSystemTime(&st2);
-  } while (memcmp(&st1, &st2, sizeof(SYSTEMTIME)) == 0);
-  uint32_t dwHash1 =
-      FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st1, sizeof(st1)), true);
-  uint32_t dwHash2 =
-      FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st2, sizeof(st2)), true);
-  ::srand((dwHash1 << 16) | (uint32_t)dwHash2);
-#else
-  time_t tmLast = time(nullptr);
-  time_t tmCur;
-  while ((tmCur = time(nullptr)) == tmLast)
-    continue;
+  SYSTEMTIME st;
+  GetSystemTime(&st);
+  seed ^= static_cast<uint32_t>(st.wSecond) * 1000000;
+  seed ^= static_cast<uint32_t>(st.wMilliseconds) * 1000;
+  seed ^= GetCurrentProcessId();
+#else   // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+  struct timeval tv;
+  gettimeofday(&tv, 0);
+  seed ^= static_cast<uint32_t>(tv.tv_sec) * 1000000;
+  seed ^= static_cast<uint32_t>(tv.tv_usec);
+  seed ^= static_cast<uint32_t>(getpid());
+#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+  return seed;
+}
 
-  ::srand((tmCur << 16) | (tmLast & 0xFFFF));
-#endif
-  while (iCount-- > 0)
-    *pBuffer++ = static_cast<uint32_t>((::rand() << 16) | (::rand() & 0xFFFF));
+void* ContextFromNextGlobalSeed() {
+  if (!g_bHaveGlobalSeed) {
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+    if (!GenerateSeedFromCryptoRandom(&g_nGlobalSeed))
+      g_nGlobalSeed = GenerateSeedFromEnvironment();
+#else   // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+    g_nGlobalSeed = GenerateSeedFromEnvironment();
+#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+    g_bHaveGlobalSeed = true;
+  }
+  return FX_Random_MT_Start(++g_nGlobalSeed);
 }
 
 }  // namespace
 
 void* FX_Random_MT_Start(uint32_t dwSeed) {
   MTContext* pContext = FX_Alloc(MTContext, 1);
-  pContext->mt[0] = dwSeed;
-  uint32_t& i = pContext->mti;
   uint32_t* pBuf = pContext->mt;
-  for (i = 1; i < MT_N; i++)
+  pBuf[0] = dwSeed;
+  for (uint32_t i = 1; i < MT_N; i++)
     pBuf[i] = (1812433253UL * (pBuf[i - 1] ^ (pBuf[i - 1] >> 30)) + i);
 
-  pContext->bHaveSeed = true;
+  pContext->mti = MT_N;
   return pContext;
 }
 
 uint32_t FX_Random_MT_Generate(void* pContext) {
-  ASSERT(pContext);
-
   MTContext* pMTC = static_cast<MTContext*>(pContext);
-  uint32_t v;
-  static uint32_t mag[2] = {0, MT_Matrix_A};
-  uint32_t& mti = pMTC->mti;
   uint32_t* pBuf = pMTC->mt;
-  if ((int)mti < 0 || mti >= MT_N) {
-    if (mti > MT_N && !pMTC->bHaveSeed)
-      return 0;
-
+  uint32_t v;
+  if (pMTC->mti >= MT_N) {
+    static const uint32_t mag[2] = {0, MT_Matrix_A};
     uint32_t kk;
     for (kk = 0; kk < MT_N - MT_M; kk++) {
       v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask);
@@ -110,9 +109,9 @@
     }
     v = (pBuf[MT_N - 1] & MT_Upper_Mask) | (pBuf[0] & MT_Lower_Mask);
     pBuf[MT_N - 1] = pBuf[MT_M - 1] ^ (v >> 1) ^ mag[v & 1];
-    mti = 0;
+    pMTC->mti = 0;
   }
-  v = pBuf[mti++];
+  v = pBuf[pMTC->mti++];
   v ^= (v >> 11);
   v ^= (v << 7) & 0x9d2c5680UL;
   v ^= (v << 15) & 0xefc60000UL;
@@ -121,19 +120,11 @@
 }
 
 void FX_Random_MT_Close(void* pContext) {
-  ASSERT(pContext);
   FX_Free(pContext);
 }
 
 void FX_Random_GenerateMT(uint32_t* pBuffer, int32_t iCount) {
-  uint32_t dwSeed;
-#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
-  if (!GenerateCryptoRandom(&dwSeed, 1))
-    Random_GenerateBase(&dwSeed, 1);
-#else
-  Random_GenerateBase(&dwSeed, 1);
-#endif
-  void* pContext = FX_Random_MT_Start(dwSeed);
+  void* pContext = ContextFromNextGlobalSeed();
   while (iCount-- > 0)
     *pBuffer++ = FX_Random_MT_Generate(pContext);
 
diff --git a/core/fxcrt/fx_random_unittest.cpp b/core/fxcrt/fx_random_unittest.cpp
new file mode 100644
index 0000000..607f140
--- /dev/null
+++ b/core/fxcrt/fx_random_unittest.cpp
@@ -0,0 +1,24 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxcrt/fx_random.h"
+
+#include <array>
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(FX_Random, GenerateMT3600times) {
+  // Prove this doesn't spin wait for a second each time.
+  // Since our global seeds are sequential, they wont't collide once
+  // seeded until 2^32 calls, and if the PNRG is any good, we won't
+  // get the same sequence from different seeds, esp. with this few
+  // iterations.
+  std::set<std::array<uint32_t, 16>> seen;
+  std::array<uint32_t, 16> current;
+  for (int i = 0; i < 3600; ++i) {
+    FX_Random_GenerateMT(current.data(), 16);
+    EXPECT_TRUE(seen.insert(current).second);
+  }
+}