Bug 1402282 - Change jemalloc to use secure random arena ids r=glandium
☠☠ backed out by bb25f71f2e4e ☠ ☠
authorChris Martin <cmartin@mozilla.com>
Mon, 05 Nov 2018 00:27:31 +0000
changeset 444437 db7059b57f929b08f3367c7815ba08b76728fe6b
parent 444436 cea1d44ac77657bcb92172ceab3abaa6bbb7743f
child 444438 f57f2d7a928c8983bb34644c58ccae5c0ef9a75c
push id109593
push usernbeleuzu@mozilla.com
push dateMon, 05 Nov 2018 21:54:22 +0000
treeherdermozilla-inbound@c58b8835f297 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1402282
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1402282 - Change jemalloc to use secure random arena ids r=glandium Previously the id for a new arena was just a counter that increased by one every time. For hardening purposes, we want to make the new counter a secure random ID, so an attacker will have a more difficult time finding the memory they are looking for. Differential Revision: https://phabricator.services.mozilla.com/D10158
memory/build/mozjemalloc.cpp
memory/replace/logalloc/replay/Replay.cpp
memory/replace/logalloc/replay/moz.build
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -127,16 +127,17 @@
 #include "mozilla/Alignment.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DoublyLinkedList.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
+#include "mozilla/RandomNum.h"
 #include "mozilla/Sprintf.h"
 // Note: MozTaggedAnonymousMmap() could call an LD_PRELOADed mmap
 // instead of the one defined here; use only MozTagAnonymousMemory().
 #include "mozilla/TaggedAnonymousMemory.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/fallible.h"
@@ -1156,18 +1157,19 @@ public:
 
   Iterator iter() { return Iterator(&mArenas, &mPrivateArenas); }
 
   inline arena_t* GetDefault() { return mDefaultArena; }
 
   Mutex mLock;
 
 private:
+  inline arena_t* GetByIdInternal(arena_id_t aArenaId, bool aIsPrivate);
+
   arena_t* mDefaultArena;
-  arena_id_t mLastArenaId;
   Tree mArenas;
   Tree mPrivateArenas;
 };
 
 static ArenaCollection gArenas;
 
 // ******
 // Chunks.
@@ -3730,18 +3732,37 @@ ArenaCollection::CreateArena(bool aIsPri
     // In practice, this is an extremely unlikely failure.
     _malloc_message(_getprogname(), ": (malloc) Error initializing arena\n");
 
     return mDefaultArena;
   }
 
   MutexAutoLock lock(mLock);
 
-  // TODO: Use random Ids.
-  ret->mId = mLastArenaId++;
+  ret->mId = [&] {
+    // Generate a cryptographically-secure random id for the new arena
+    // If an attacker manages to get control of the process, this should make
+    // it more difficult for them to "guess" the ID of another memory arena,
+    // stopping them from getting data they may want
+
+    while (true) {
+      mozilla::Maybe<uint64_t> maybeRandomId = mozilla::RandomUint64();
+      MOZ_RELEASE_ASSERT(maybeRandomId.isSome());
+
+      // Keep looping until we ensure that the random number we just generated
+      // isn't already in use by another active arena
+      arena_t* existingArena =
+        GetByIdInternal(maybeRandomId.value(), aIsPrivate);
+
+      if (!existingArena) {
+        return maybeRandomId.value();
+      }
+    }
+  }();
+
   (aIsPrivate ? mPrivateArenas : mArenas).Insert(ret);
   return ret;
 }
 
 // End arena.
 // ***************************************************************************
 // Begin general internal functions.
 
@@ -4557,28 +4578,35 @@ MozJemalloc::jemalloc_free_dirty_pages(v
     MutexAutoLock lock(gArenas.mLock);
     for (auto arena : gArenas.iter()) {
       MutexAutoLock arena_lock(arena->mLock);
       arena->Purge(true);
     }
   }
 }
 
+// ArenaCollection::mLock must be locked before calling this
+inline arena_t*
+ArenaCollection::GetByIdInternal(arena_id_t aArenaId, bool aIsPrivate)
+{
+  // Use AlignedStorage2 to avoid running the arena_t constructor, while
+  // we only need it as a placeholder for mId.
+  mozilla::AlignedStorage2<arena_t> key;
+  key.addr()->mId = aArenaId;
+  return (aIsPrivate ? mPrivateArenas : mArenas).Search(key.addr());
+}
+
 inline arena_t*
 ArenaCollection::GetById(arena_id_t aArenaId, bool aIsPrivate)
 {
   if (!malloc_initialized) {
     return nullptr;
   }
-  // Use AlignedStorage2 to avoid running the arena_t constructor, while
-  // we only need it as a placeholder for mId.
-  mozilla::AlignedStorage2<arena_t> key;
-  key.addr()->mId = aArenaId;
   MutexAutoLock lock(mLock);
-  arena_t* result = (aIsPrivate ? mPrivateArenas : mArenas).Search(key.addr());
+  arena_t* result = GetByIdInternal(aArenaId, aIsPrivate);
   MOZ_RELEASE_ASSERT(result);
   return result;
 }
 
 template<>
 inline arena_id_t
 MozJemalloc::moz_create_arena_with_params(arena_params_t* aParams)
 {
--- a/memory/replace/logalloc/replay/Replay.cpp
+++ b/memory/replace/logalloc/replay/Replay.cpp
@@ -295,22 +295,16 @@ MOZ_BEGIN_EXTERN_C
 #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
 #include "malloc_decls.h"
 
 #define MALLOC_DECL(name, return_type, ...) return_type name(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 
 #ifdef ANDROID
-/* mozjemalloc uses MozTagAnonymousMemory, which doesn't have an inline
- * implementation on Android */
-void
-MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag)
-{
-}
 
 /* mozjemalloc and jemalloc use pthread_atfork, which Android doesn't have.
  * While gecko has one in libmozglue, the replay program can't use that.
  * Since we're not going to fork anyways, make it a dummy function. */
 int
 pthread_atfork(void (*aPrepare)(void),
                void (*aParent)(void),
                void (*aChild)(void))
--- a/memory/replace/logalloc/replay/moz.build
+++ b/memory/replace/logalloc/replay/moz.build
@@ -3,25 +3,27 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 Program('logalloc-replay')
 
 SOURCES += [
     '/mfbt/Assertions.cpp',
+    '/mfbt/Poison.cpp',
+    '/mfbt/RandomNum.cpp',
+    '/mfbt/TaggedAnonymousMemory.cpp',
     '/mfbt/Unused.cpp',
     'Replay.cpp',
 ]
 
 if CONFIG['MOZ_REPLACE_MALLOC_STATIC'] and CONFIG['MOZ_DMD']:
     UNIFIED_SOURCES += [
         '/mfbt/HashFunctions.cpp',
         '/mfbt/JSONWriter.cpp',
-        '/mfbt/Poison.cpp',
         '/mozglue/misc/StackWalk.cpp',
     ]
 
 if not CONFIG['MOZ_REPLACE_MALLOC_STATIC']:
     SOURCES += [
         '../FdPrintf.cpp',
     ]