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_
|