Coverage for /Syzygy/agent/asan/heap_managers/block_heap_manager.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%770.C++source

Line-by-line coverage:

   1    :  // Copyright 2014 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Implementation of a heap manager that allocates blocks.
  16    :  
  17    :  #ifndef SYZYGY_AGENT_ASAN_HEAP_MANAGERS_BLOCK_HEAP_MANAGER_H_
  18    :  #define SYZYGY_AGENT_ASAN_HEAP_MANAGERS_BLOCK_HEAP_MANAGER_H_
  19    :  
  20    :  #include <windows.h>
  21    :  
  22    :  #include <memory>
  23    :  #include <unordered_map>
  24    :  #include <utility>
  25    :  
  26    :  #include "base/logging.h"
  27    :  #include "syzygy/agent/asan/block_utils.h"
  28    :  #include "syzygy/agent/asan/error_info.h"
  29    :  #include "syzygy/agent/asan/heap.h"
  30    :  #include "syzygy/agent/asan/heap_manager.h"
  31    :  #include "syzygy/agent/asan/quarantine.h"
  32    :  #include "syzygy/agent/asan/registry_cache.h"
  33    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  34    :  #include "syzygy/agent/asan/heap_managers/deferred_free_thread.h"
  35    :  #include "syzygy/agent/asan/memory_notifiers/shadow_memory_notifier.h"
  36    :  #include "syzygy/agent/asan/quarantines/sharded_quarantine.h"
  37    :  #include "syzygy/agent/common/stack_capture.h"
  38    :  #include "syzygy/common/asan_parameters.h"
  39    :  
  40    :  namespace agent {
  41    :  namespace asan {
  42    :  
  43    :  // Forward declarations
  44    :  namespace heaps {
  45    :  
  46    :  class ZebraBlockHeap;
  47    :  
  48    :  }  // namespace heaps
  49    :  
  50    :  namespace heap_managers {
  51    :  
  52    :  // A block heap manager is an implementation of a heap manager that allocates
  53    :  // and manages blocks.
  54    :  //
  55    :  // It is responsible for maintaining the state of the shadow memory, and thus
  56    :  // updating it when a block's state changes. This also takes care of maintaining
  57    :  // a quarantine of freed blocks.
  58    :  //
  59    :  // When the user requests a new heap, it will receive a pointer to a
  60    :  // SimpleBlockHeap by default. However the goal of this manager is to
  61    :  // automatically choose the most appropriate heap for a given allocation so the
  62    :  // actual heap that serves an allocation can be different from the one returned
  63    :  // to the user.
  64    :  //
  65    :  // The zebra heap is created once, when enabled for the first time, with a
  66    :  // specified size. It can't be resized after creation. Disabling the zebra
  67    :  // heap only disables allocations on it, deallocations will continue to work.
  68    :  class BlockHeapManager : public HeapManagerInterface {
  69    :   public:
  70    :    // Constructor.
  71    :    // @param shadow The shadow memory to use.
  72    :    // @param stack_cache The stack cache to use.
  73    :    // @param memory_notifier The memory notifier to use.
  74    :    BlockHeapManager(Shadow* shadow,
  75    :                     StackCaptureCache* stack_cache,
  76    :                     MemoryNotifierInterface* memory_notifier);
  77    :  
  78    :    // Destructor.
  79    :    virtual ~BlockHeapManager();
  80    :  
  81    :    // Initializes this block heap manager. Must be called prior to any
  82    :    // HeapManagerInterface functions. Parameters may be set prior to this.
  83    :    void Init();
  84    :  
  85    :    // @name HeapManagerInterface functions.
  86    :    // @{
  87    :     HeapId CreateHeap() override;
  88    :     bool DestroyHeap(HeapId heap_id) override;
  89    :     void* Allocate(HeapId heap_id, uint32_t bytes) override;
  90    :     bool Free(HeapId heap_id, void* alloc) override;
  91    :     uint32_t Size(HeapId heap_id, const void* alloc) override;
  92    :     void Lock(HeapId heap_id) override;
  93    :     void Unlock(HeapId heap_id) override;
  94    :     void BestEffortLockAll() override;
  95    :     void UnlockAll() override;
  96    :    // @}
  97    :  
  98    :    // Set the parameters of this heap manager.
  99    :    // @param trailer_padding_size The trailer padding size, in bytes.
 100    :    void set_parameters(const ::common::AsanParameters& parameters);
 101    :  
 102    :    // Get the parameters.
 103  E :    ::common::AsanParameters parameters() {
 104  E :      return parameters_;
 105  E :    }
 106    :  
 107    :    // Sets the callback that this heap will invoke when heap corruption is
 108    :    // encountered.
 109    :    // @param heap_error_callback The callback to be invoked when heap
 110    :    //     corruption is encountered.
 111  E :    void SetHeapErrorCallback(HeapErrorCallback heap_error_callback) {
 112  E :      heap_error_callback_ = heap_error_callback;
 113  E :    }
 114    :  
 115    :    // Returns the process heap ID.
 116  E :    HeapId process_heap() { return process_heap_id_; }
 117    :  
 118    :    // Returns the allocation-filter flag value.
 119    :    // @returns the allocation-filter flag value.
 120    :    // @note The flag is stored per-thread using TLS. Multiple threads do not
 121    :    //     share the same flag.
 122    :    bool allocation_filter_flag() const;
 123    :  
 124    :    // Sets the allocation-filter flag to the specified value.
 125    :    // @param value the new value for the flag.
 126    :    // @note The flag is stored per-thread using TLS. Multiple threads do not
 127    :    //     share the same flag.
 128    :    void set_allocation_filter_flag(bool value);
 129    :  
 130    :    // Enables the deferred free thread mechanism. Must not be called if the
 131    :    // thread is already running. Typical usage is to enable the thread at startup
 132    :    // and disable it at shutdown.
 133    :    void EnableDeferredFreeThread();
 134    :  
 135    :    // Disables the deferred free thread mechanism. Must be called before the
 136    :    // destructor if the thread is enabled. Must also never be called if the
 137    :    // thread is not enabled.
 138    :    void DisableDeferredFreeThread();
 139    :  
 140    :    // @returns true if the deferred thread is currently running.
 141    :    bool IsDeferredFreeThreadRunning();
 142    :  
 143    :   protected:
 144    :    // This allows the runtime access to our internals, necessary for crash
 145    :    // processing.
 146    :    friend class AsanRuntime;
 147    :  
 148    :    // @name Functions intended for use exclusively by the AsanRuntime for
 149    :    //     introspection during crash processing.
 150    :    // @{
 151    :    HeapType GetHeapTypeUnlocked(HeapId heap_id);
 152    :    // @}
 153    :  
 154    :    // The type of quarantine that we use internally.
 155    :    using ShardedBlockQuarantine =
 156    :        quarantines::ShardedQuarantine<CompactBlockInfo,
 157    :                                       GetTotalBlockSizeFunctor,
 158    :                                       GetBlockHashFunctor,
 159    :                                       kQuarantineDefaultShardingFactor>;
 160    :  
 161    :    // A map associating a block heap with its underlying heap.
 162    :    using UnderlyingHeapMap =
 163    :        std::unordered_map<BlockHeapInterface*, HeapInterface*>;
 164    :  
 165    :    // A map associating a block heap with a pair containing the quarantine it
 166    :    // will use and a bit indicating if it's dying. Many heaps may share a single
 167    :    // quarantine.
 168    :    struct HeapMetadata {
 169    :      BlockQuarantineInterface* quarantine;
 170    :      bool is_dying;
 171    :    };
 172    :    using HeapQuarantineMap =
 173    :        std::unordered_map<BlockHeapInterface*, HeapMetadata>;
 174    :    using HeapQuarantinePair = BlockHeapManager::HeapQuarantineMap::value_type;
 175    :  
 176    :    using StackId = agent::common::StackCapture::StackId;
 177    :  
 178    :    // Causes the heap manager to tear itself down. If the heap manager
 179    :    // encounters corrupt blocks while tearing itself dow it will report an
 180    :    // error. This will in turn cause the asan runtime to call back into itself
 181    :    // and access the block heap manager. Thus, the block heap manager needs to
 182    :    // still be alive while this process is occurring. Hence, the need to
 183    :    // separate the work of tearing down the heap manager from its destructor.
 184    :    void TearDownHeapManager();
 185    :  
 186    :    // Given the result of an HeapQuarantineMap insert or find, returns a heap id.
 187    :    // @param iterator An iterator to a heap.
 188    :    // @param insert_result The result of a call to heaps_.insert.
 189    :    // @returns the ID associated with the inserted heap.
 190    :    HeapId GetHeapId(
 191    :        HeapQuarantineMap::iterator iterator) const;
 192    :    HeapId GetHeapId(
 193    :        const std::pair<HeapQuarantineMap::iterator, bool>& insert_result) const;
 194    :  
 195    :    // @name Heap validation. There are multiple ways to do this because of the
 196    :    //     need to do this during crash processing, when locks are already
 197    :    //     implicitly acquired. As such, the runtime has been made a friend of
 198    :    //     this class.
 199    :    // Determines if a heap ID is valid.
 200    :    // @param heap_id The heap_id to validate.
 201    :    // @param allow_dying If true then also consider heaps that are in the
 202    :    //     process of dying. Otherwise, only consider live heaps.
 203    :    // @returns true if the given heap id is valid.
 204    :    // @note The unsafe variants can raise access violations.
 205    :    bool IsValidHeapIdUnsafe(HeapId heap_id, bool allow_dying);
 206    :    bool IsValidHeapIdUnsafeUnlocked(HeapId heap_id, bool allow_dying);
 207    :    bool IsValidHeapId(HeapId heap_id, bool allow_dying);
 208    :    bool IsValidHeapIdUnlocked(HeapId heap_id, bool allow_dying);
 209    :  
 210    :    // Helpers for the above functions. This is split into two to keep the
 211    :    // locking as narrow as possible.
 212    :    // @param hq The heap quarantine pair being queried.
 213    :    // @param allow_dying If true then also consider heaps that are in the
 214    :    //     process of dying. Otherwise, only consider live heaps.
 215    :    bool IsValidHeapIdUnsafeUnlockedImpl1(HeapQuarantinePair* hq);
 216    :    bool IsValidHeapIdUnlockedImpl1(HeapQuarantinePair* hq);
 217    :    bool IsValidHeapIdUnlockedImpl2(HeapQuarantinePair* hq, bool allow_dying);
 218    :    // @}
 219    :  
 220    :    // Given a heap ID, returns the underlying heap.
 221    :    // @param heap_id The ID of the heap to look up.
 222    :    // @returns a pointer to the heap implementation.
 223    :    // @note DCHECKs on invalid input.
 224    :    static BlockHeapInterface* GetHeapFromId(HeapId heap_id);
 225    :  
 226    :    // Given a heap ID, returns the associated quarantine.
 227    :    // @param heap_id The ID of the heap whose quarantine is to be looked up.
 228    :    // @returns a pointer to the quarantine implementation.
 229    :    // @note DCHECKs on invalid input.
 230    :    static BlockQuarantineInterface* GetQuarantineFromId(HeapId heap_id);
 231    :  
 232    :    // Propagates the parameters to the appropriate modules.
 233    :    // @note This function is responsible for acquiring lock_ when necessary.
 234    :    void PropagateParameters();
 235    :  
 236    :    // Destroy a heap and flush its quarantine. If this heap has an underlying
 237    :    // heap it'll also destroy it. All the blocks belonging to this heap that are
 238    :    // in the quarantine will be freed.
 239    :    //
 240    :    // @param heap The heap to destroy.
 241    :    // @param quarantine The quarantine of this heap.
 242    :    // @returns true on success, false otherwise.
 243    :    // @note The heap pointer will be invalid if this function succeeds.
 244    :    bool DestroyHeapContents(BlockHeapInterface* heap,
 245    :                             BlockQuarantineInterface* quarantine);
 246    :  
 247    :    // Removes a heap from the manager, then frees it and any resources
 248    :    // associated with it. This does not remove the heap pointer from the
 249    :    // heaps_ structure.
 250    :    // @note This must be called under lock_.
 251    :    void DestroyHeapResourcesUnlocked(BlockHeapInterface* heap,
 252    :                                      BlockQuarantineInterface* quarantine);
 253    :  
 254    :    // Trim the specified quarantine until its color is |stop_color| or lower. If
 255    :    // parameters_.quarantine_size is 0 then the quarantine is flushed.
 256    :    // @param stop_color The target color at which the trimming ends.
 257    :    // @param quarantine The quarantine to trim.
 258    :    // TODO(peterssen): Change the 0-size contract. The quarantine 'contract'
 259    :    //    establish that when the size is 0, it means unlimited, this is rather
 260    :    //    awkward since trimming with size 0 should flush the quarantine.
 261    :    void TrimQuarantine(TrimColor stop_color,
 262    :                        BlockQuarantineInterface* quarantine);
 263    :  
 264    :    // Free a block.
 265    :    // @param obj The object to be freed.
 266    :    void FreeBlock(const BlockQuarantineInterface::Object& obj);
 267    :  
 268    :    // Free a block that might be corrupt. If the block is corrupt first reports
 269    :    // an error before safely releasing the block.
 270    :    // @param block_info The information about this block.
 271    :    // @returns true if the block has been successfully freed, false otherwise.
 272    :    bool FreePotentiallyCorruptBlock(BlockInfo* block_info);
 273    :  
 274    :    // Free a corrupt block. This takes care of cleaning its metadata before
 275    :    // trying to free it.
 276    :    // @param block_info The information about this block.
 277    :    // @returns true if the block has been successfully freed, false otherwise.
 278    :    bool FreeCorruptBlock(BlockInfo* block_info);
 279    :  
 280    :    // Free an allocated block. This should be called when a block is removed from
 281    :    // the quarantine or directly freed. This takes care of updating the shadow
 282    :    // memory and releasing the resources acquired by this block (like its stack
 283    :    // traces). The block should either not be corrupt or cleaned from its unsafe
 284    :    // metadata.
 285    :    // @param block_info The information about this block.
 286    :    // @returns true on success, false otherwise.
 287    :    bool FreePristineBlock(BlockInfo* block_info);
 288    :  
 289    :    // Free an unguarded allocation.
 290    :    // @param heap_id A hint about the heap that might contain this allocation.
 291    :    // @param alloc The allocation to be freed.
 292    :    // @returns true if the allocation has been successfully freed, false
 293    :    //     otherwise.
 294    :    bool FreeUnguardedAlloc(HeapId heap_id, void* alloc);
 295    :  
 296    :    // Clears the metadata of a corrupt block. After calling this function the
 297    :    // block can safely be passed to FreeBlock.
 298    :    // @param block_info The information about this block.
 299    :    void ClearCorruptBlockMetadata(BlockInfo* block_info);
 300    :  
 301    :    // Reports a heap error via the heap error callback. This is for originating
 302    :    // errors that are detected while performing operations on a heap metadata.
 303    :    // Read/write errors are detected outside of the manager, and query the heap
 304    :    // for information about the error itself.
 305    :    // @param address The address that was being accessed/manipulating when the
 306    :    //     error was detected.
 307    :    // @param kind The type of error encountered.
 308    :    void ReportHeapError(void* address, BadAccessKind kind);
 309    :  
 310    :    // Initializes internal heap structures, if not yet done. This must be called
 311    :    // before PropagateParameters and InitProcessHeap.
 312    :    void InitInternalHeap();
 313    :  
 314    :    // Initialize the process heap. This is only meant to be called at
 315    :    // initialization time when process_heap_ is NULL.
 316    :    // Exposed for unittesting.
 317    :    void InitProcessHeap();
 318    :  
 319    :    // Determines if the large block heap should be used for an allocation of
 320    :    // the given size.
 321    :    // @param bytes The allocation size.
 322    :    // @returns true if the large block heap should be used for this allocation,
 323    :    //     false otherwise.
 324    :    bool MayUseLargeBlockHeap(size_t bytes) const;
 325    :  
 326    :    // Determines if the zebra block heap should be used for an allocation of
 327    :    // the given size.
 328    :    // @param bytes The allocation size.
 329    :    // @returns true if the zebra heap should be used for this allocation, false
 330    :    //     otherwise.
 331    :    bool MayUseZebraBlockHeap(size_t bytes) const;
 332    :  
 333    :    // Indicates if a corrupt block error should be reported.
 334    :    // @param block_info The corrupt block.
 335    :    // @returns true if an error should be reported, false otherwise.
 336    :    bool ShouldReportCorruptBlock(const BlockInfo* block_info);
 337    :  
 338    :    // Called to check if the quarantine needs to be trimmed. This will either
 339    :    // schedule asynchronous trimming, execute synchronous trimming, do both or do
 340    :    // neither, depending on the value of |trim_status|.
 341    :    // @param quarantine The quarantine to be trimmed.
 342    :    // @param trim_status The status returned by the push.
 343    :    void TrimOrScheduleIfNecessary(TrimStatus trim_status,
 344    :                                   BlockQuarantineInterface* quarantine);
 345    :  
 346    :    // Used by TrimOrScheduleIfNecessary to signal the deferred free thread that
 347    :    // the quarantine needs trimming (ie. asynchronous trimming).
 348    :    void DeferredFreeThreadSignalWork();
 349    :  
 350    :    // Invoked by the deferred free thread when it is signaled that the quarantine
 351    :    // needs trimming.
 352    :    void DeferredFreeDoWork();
 353    :  
 354    :    // Implementation of EnableDeferredFreeThread that takes the callback. Used
 355    :    // also by tests to override the callback.
 356    :    // @param deferred_free_callback The callback.
 357    :    void EnableDeferredFreeThreadWithCallback(
 358    :        DeferredFreeThread::Callback deferred_free_callback);
 359    :  
 360    :    // Returns the ID of the deferred free thread. Must not be called if the
 361    :    // thread is not running.
 362    :    // @returns the thread ID.
 363    :    base::PlatformThreadId GetDeferredFreeThreadId();
 364    :  
 365    :    // The shadow memory that is notified by all activity in this heap manager.
 366    :    Shadow* shadow_;
 367    :  
 368    :    // The stack cache used to store the stack traces.
 369    :    StackCaptureCache* stack_cache_;
 370    :  
 371    :    // The memory notifier to use.
 372    :    MemoryNotifierInterface* memory_notifier_;
 373    :  
 374    :    // Protects concurrent access to the heap manager internals.
 375    :    base::Lock lock_;
 376    :  
 377    :    // Indicates if 'Init' has been called.
 378    :    bool initialized_;  // Under lock_.
 379    :  
 380    :    // Contains the heaps owned by this manager.
 381    :    HeapQuarantineMap heaps_;  // Under lock_.
 382    :  
 383    :    // The quarantine shared by the heaps created by this manager. This is also
 384    :    // used by the LargeBlockHeap.
 385    :    ShardedBlockQuarantine shared_quarantine_;
 386    :  
 387    :    // Map the block heaps to their underlying heap.
 388    :    UnderlyingHeapMap underlying_heaps_map_;  // Under lock_.
 389    :  
 390    :    // The parameters of this heap manager.
 391    :    ::common::AsanParameters parameters_;
 392    :  
 393    :    // The callback this manager uses to expose internal state errors. These are
 394    :    // caused by uninstrumented code (system libraries, etc), thus aren't caught
 395    :    // at their source. Catching their side effect as early as possible allows the
 396    :    // recovery of some useful debugging information.
 397    :    HeapErrorCallback heap_error_callback_;
 398    :  
 399    :    // The process heap.
 400    :    //
 401    :    // TODO(sebmarchand): Put the interception of the process heap behind a flag
 402    :    //     and return the original process heap by default.
 403    :    BlockHeapInterface* process_heap_;
 404    :    HeapInterface* process_heap_underlying_heap_;
 405    :    HeapId process_heap_id_;
 406    :  
 407    :    // The heap that gets used for allocation of internal data structures.
 408    :    std::unique_ptr<HeapInterface> internal_win_heap_;
 409    :    std::unique_ptr<HeapInterface> internal_heap_;
 410    :  
 411    :    // Hold the single ZebraBlockHeap instance used by this heap manager.
 412    :    // The lifetime management of the zebra heap is provided by the
 413    :    // HeapQuarantineMap, this is simply a useful pointer for finding the
 414    :    // zebra heap directly.
 415    :    heaps::ZebraBlockHeap* zebra_block_heap_;
 416    :    HeapId zebra_block_heap_id_;
 417    :  
 418    :    // The ID of the large block heap. Allows accessing it directly.
 419    :    HeapId large_block_heap_id_;
 420    :  
 421    :    // Stores the AllocationFilterFlag TLS slot.
 422    :    DWORD allocation_filter_flag_tls_;
 423    :  
 424    :    // A list of all heaps whose locks were acquired by the last call to
 425    :    // BestEffortLockAll. This uses the internal heap, otherwise the default
 426    :    // allocator makes use of the process heap. The process heap may itself
 427    :    // be locked when we try to use this, hence a deadlock can occur. This ends
 428    :    // up being a null terminated array of HeapInterface*.
 429    :    // Under lock_.
 430    :    HeapInterface** locked_heaps_;
 431    :  
 432    :    // Indicates if we use page protection to prevent invalid accesses to a block.
 433    :    bool enable_page_protections_;
 434    :  
 435    :    // The registry cache that we use to store the allocation stack ID of the
 436    :    // corrupt block for which we've already reported an error.
 437    :    RegistryCache corrupt_block_registry_cache_;
 438    :  
 439    :   private:
 440    :    // Background thread that takes care of trimming the quarantine
 441    :    // asynchronously.
 442    :    base::Lock deferred_free_thread_lock_;
 443    :    // Under deferred_free_thread_lock_.
 444    :    std::unique_ptr<DeferredFreeThread> deferred_free_thread_;
 445    :  
 446    :    DISALLOW_COPY_AND_ASSIGN(BlockHeapManager);
 447    :  };
 448    :  
 449    :  }  // namespace heap_managers
 450    :  }  // namespace asan
 451    :  }  // namespace agent
 452    :  
 453    :  #endif  // SYZYGY_AGENT_ASAN_HEAP_MANAGERS_BLOCK_HEAP_MANAGER_H_

Coverage information generated Fri Jul 29 11:00:21 2016.