Changeset 143488 in webkit


Ignore:
Timestamp:
Feb 20, 2013 1:09:16 PM (11 years ago)
Author:
oliver@apple.com
Message:

Moar hardening
https://bugs.webkit.org/show_bug.cgi?id=110275

Reviewed by Mark Hahnenberg.

We now poison objects when they get freed, and verify that
any object that is being freed is not poisoned. If the
object looks like it's poisoned we validate the freelist,
and ensure the object is not already present. If it is
we crash.

On allocation, we ensure that the object being allocated
is poisoned, then clear the poisoning fields.

  • wtf/FastMalloc.cpp:

(WTF::internalEntropyValue):
(WTF):
(WTF::freedObjectStartPoison):
(WTF::freedObjectEndPoison):
(TCMalloc_ThreadCache_FreeList):
(WTF::TCMalloc_ThreadCache_FreeList::Validate):
(WTF::TCMalloc_Central_FreeList::Populate):
(WTF::TCMalloc_ThreadCache::Allocate):
(WTF::TCMalloc_ThreadCache::Deallocate):
(WTF::TCMalloc_ThreadCache::CreateCacheIfNecessary):

Location:
trunk/Source/WTF
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r143424 r143488  
     12013-02-20  Oliver Hunt  <oliver@apple.com>
     2
     3        Moar hardening
     4        https://bugs.webkit.org/show_bug.cgi?id=110275
     5
     6        Reviewed by Mark Hahnenberg.
     7
     8        We now poison objects when they get freed, and verify that
     9        any object that is being freed is not poisoned.  If the
     10        object looks like it's poisoned we validate the freelist,
     11        and ensure the object is not already present.  If it is
     12        we crash.
     13
     14        On allocation, we ensure that the object being allocated
     15        is poisoned, then clear the poisoning fields.
     16
     17        * wtf/FastMalloc.cpp:
     18        (WTF::internalEntropyValue):
     19        (WTF):
     20        (WTF::freedObjectStartPoison):
     21        (WTF::freedObjectEndPoison):
     22        (TCMalloc_ThreadCache_FreeList):
     23        (WTF::TCMalloc_ThreadCache_FreeList::Validate):
     24        (WTF::TCMalloc_Central_FreeList::Populate):
     25        (WTF::TCMalloc_ThreadCache::Allocate):
     26        (WTF::TCMalloc_ThreadCache::Deallocate):
     27        (WTF::TCMalloc_ThreadCache::CreateCacheIfNecessary):
     28
    1292013-02-19  Sheriff Bot  <webkit.review.bot@gmail.com>
    230
  • trunk/Source/WTF/wtf/FastMalloc.cpp

    r143424 r143488  
    545545};
    546546
    547 static ALWAYS_INLINE uintptr_t internalEntropyValue() {
     547static ALWAYS_INLINE uintptr_t internalEntropyValue()
     548{
    548549    static uintptr_t value = EntropySource<sizeof(uintptr_t)>::value();
    549550    ASSERT(value);
     
    555556#define XOR_MASK_PTR_WITH_KEY(ptr, key, entropy) (reinterpret_cast<typeof(ptr)>(reinterpret_cast<uintptr_t>(ptr)^(ROTATE_VALUE(reinterpret_cast<uintptr_t>(key), MaskKeyShift)^entropy)))
    556557
     558
     559static ALWAYS_INLINE uint32_t freedObjectStartPoison()
     560{
     561    static uint32_t value = EntropySource<sizeof(uint32_t)>::value() | 1;
     562    ASSERT(value);
     563    return value;
     564}
     565
     566static ALWAYS_INLINE uint32_t freedObjectEndPoison()
     567{
     568    static uint32_t value = EntropySource<sizeof(uint32_t)>::value() | 1;
     569    ASSERT(value);
     570    return value;
     571}
     572
     573#define PTR_TO_UINT32(ptr) static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr))
     574#define END_POISON_INDEX(allocationSize) (((allocationSize) - sizeof(uint32_t)) / sizeof(uint32_t))
     575#define POISON_ALLOCATION(allocation, allocationSize) do { \
     576    reinterpret_cast<uint32_t*>(allocation)[0] = 1; \
     577    reinterpret_cast<uint32_t*>(allocation)[1] = 1; \
     578    if (allocationSize < 4 * sizeof(uint32_t)) \
     579        break; \
     580    reinterpret_cast<uint32_t*>(allocation)[2] = 1; \
     581    reinterpret_cast<uint32_t*>(allocation)[END_POISON_INDEX(allocationSize)] = 1; \
     582} while (false);
     583
     584#define POISON_DEALLOCATION_EXPLICIT(allocation, allocationSize, startPoison, endPoison) do { \
     585    if (allocationSize < 4 * sizeof(uint32_t)) \
     586        break; \
     587    reinterpret_cast<uint32_t*>(allocation)[2] = (startPoison) ^ PTR_TO_UINT32(allocation); \
     588    reinterpret_cast<uint32_t*>(allocation)[END_POISON_INDEX(allocationSize)] = (endPoison) ^ PTR_TO_UINT32(allocation); \
     589} while (false)
     590
     591#define POISON_DEALLOCATION(allocation, allocationSize) \
     592    POISON_DEALLOCATION_EXPLICIT(allocation, allocationSize, freedObjectStartPoison(), freedObjectEndPoison())
     593
     594#define MAY_BE_POISONED(allocation, allocationSize) (((allocationSize) >= 4 * sizeof(uint32_t)) && ( \
     595    (reinterpret_cast<uint32_t*>(allocation)[2] == (freedObjectStartPoison() ^ PTR_TO_UINT32(allocation))) || \
     596    (reinterpret_cast<uint32_t*>(allocation)[END_POISON_INDEX(allocationSize)] == (freedObjectEndPoison() ^ PTR_TO_UINT32(allocation))) \
     597))
     598
     599#define IS_DEFINITELY_POISONED(allocation, allocationSize) (((allocationSize) < 4 * sizeof(uint32_t)) || ( \
     600    (reinterpret_cast<uint32_t*>(allocation)[2] == (freedObjectStartPoison() ^ PTR_TO_UINT32(allocation))) && \
     601    (reinterpret_cast<uint32_t*>(allocation)[END_POISON_INDEX(allocationSize)] == (freedObjectEndPoison() ^ PTR_TO_UINT32(allocation))) \
     602))
     603
    557604#else
     605
     606#define POISON_ALLOCATION(allocation, allocationSize)
     607#define POISON_DEALLOCATION(allocation, allocationSize)
     608#define POISON_DEALLOCATION_EXPLICIT(allocation, allocationSize, startPoison, endPoison)
     609#define MAY_BE_POISONED(allocation, allocationSize) (false)
     610#define IS_DEFINITELY_POISONED(allocation, allocationSize) (true)
    558611#define XOR_MASK_PTR_WITH_KEY(ptr, key, entropy) (((void)entropy), ((void)key), ptr)
     612
    559613#define HARDENING_ENTROPY 0
    560 #endif
    561 
     614
     615#endif
    562616
    563617//-------------------------------------------------------------------
     
    25312585  }
    25322586
     2587    // Runs through the linked list to ensure that
     2588    // we can do that, and ensures that 'missing'
     2589    // is not present
     2590    NEVER_INLINE void Validate(HardenedSLL missing) {
     2591        HardenedSLL node = list_;
     2592        while (node) {
     2593            RELEASE_ASSERT(node != missing);
     2594            node = SLL_Next(node, entropy_);
     2595        }
     2596    }
     2597
    25332598#ifdef WTF_CHANGES
    25342599  template <class Finder, class Reader>
     
    30423107  char* ptr = start + (npages << kPageShift) - ((npages << kPageShift) % size);
    30433108  int num = 0;
     3109#if ENABLE(TCMALLOC_HARDENING)
     3110  uint32_t startPoison = freedObjectStartPoison();
     3111  uint32_t endPoison = freedObjectEndPoison();
     3112#endif
     3113
    30443114  while (ptr > start) {
    30453115    ptr -= size;
    30463116    HardenedSLL node = HardenedSLL::create(ptr);
     3117    POISON_DEALLOCATION_EXPLICIT(ptr, size, startPoison, endPoison);
    30473118    SLL_SetNext(node, head, entropy_);
    30483119    head = node;
     
    30513122  ASSERT(ptr == start);
    30523123  ASSERT(ptr == head.value());
     3124  POISON_DEALLOCATION_EXPLICIT(ptr, size, startPoison, endPoison);
    30533125  span->objects = head;
    30543126  ASSERT(span->objects.value() == head.value());
     
    31163188  }
    31173189  size_ -= allocationSize;
    3118   return list->Pop();
     3190  void* result = list->Pop();
     3191  if (!result)
     3192      return 0;
     3193  RELEASE_ASSERT(IS_DEFINITELY_POISONED(result, allocationSize));
     3194  POISON_ALLOCATION(result, allocationSize);
     3195  return result;
    31193196}
    31203197
    31213198inline void TCMalloc_ThreadCache::Deallocate(HardenedSLL ptr, size_t cl) {
    3122   size_ += ByteSizeForClass(cl);
     3199  size_t allocationSize = ByteSizeForClass(cl);
     3200  size_ += allocationSize;
    31233201  FreeList* list = &list_[cl];
     3202  if (MAY_BE_POISONED(ptr.value(), allocationSize))
     3203      list->Validate(ptr);
     3204
     3205  POISON_DEALLOCATION(ptr.value(), allocationSize);
    31243206  list->Push(ptr);
    31253207  // If enough data is free, put back into central cache
     
    38163898  ASSERT_SPAN_COMMITTED(span);
    38173899  pageheap->CacheSizeClass(span->start, 0);
    3818   return
    3819       CheckedMallocResult(reinterpret_cast<void*>(span->start << kPageShift));
     3900  void* result = reinterpret_cast<void*>(span->start << kPageShift);
     3901  POISON_ALLOCATION(result, span->length << kPageShift);
     3902  return CheckedMallocResult(result);
    38203903}
    38213904
     
    38843967    } else {
    38853968      // Delete directly into central cache
     3969      size_t allocationSize = ByteSizeForClass(cl);
     3970      POISON_DEALLOCATION(ptr, allocationSize);
    38863971      SLL_SetNext(HardenedSLL::create(ptr), HardenedSLL::null(), central_cache[cl].entropy());
    38873972      central_cache[cl].InsertRange(HardenedSLL::create(ptr), HardenedSLL::create(ptr), 1);
     
    38983983    }
    38993984#endif
     3985
     3986    POISON_DEALLOCATION(ptr, span->length << kPageShift);
    39003987    pageheap->Delete(span);
    39013988  }
Note: See TracChangeset for help on using the changeset viewer.