1 : // Copyright 2012 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 the SyzyAsan instrumentation transform.
16 :
17 : #ifndef SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
18 : #define SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
19 :
20 : #include <map>
21 : #include <set>
22 : #include <string>
23 : #include <utility>
24 : #include <vector>
25 :
26 : #include "base/strings/string_piece.h"
27 : #include "syzygy/block_graph/filterable.h"
28 : #include "syzygy/block_graph/iterate.h"
29 : #include "syzygy/block_graph/analysis/liveness_analysis.h"
30 : #include "syzygy/block_graph/analysis/memory_access_analysis.h"
31 : #include "syzygy/block_graph/transforms/iterative_transform.h"
32 : #include "syzygy/block_graph/transforms/named_transform.h"
33 : #include "syzygy/common/asan_parameters.h"
34 : #include "syzygy/instrument/transforms/asan_interceptor_filter.h"
35 : #include "syzygy/instrument/transforms/asan_intercepts.h"
36 : #include "syzygy/pe/transforms/pe_add_imports_transform.h"
37 :
38 : namespace instrument {
39 : namespace transforms {
40 :
41 : // This class implements the transformation applied to each basic block.
42 : class AsanBasicBlockTransform
43 : : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
44 : AsanBasicBlockTransform>,
45 : public block_graph::Filterable {
46 : public:
47 : // Represent the different kind of access to the memory.
48 : enum MemoryAccessMode {
49 : kNoAccess,
50 : kReadAccess,
51 : kWriteAccess,
52 : kInstrAccess,
53 : kRepzAccess,
54 : kRepnzAccess,
55 : };
56 :
57 : enum StackAccessMode {
58 : kUnsafeStackAccess,
59 : kSafeStackAccess,
60 : };
61 :
62 : // Contains memory access information.
63 : struct MemoryAccessInfo {
64 : MemoryAccessMode mode;
65 : uint8_t size;
66 : uint16_t opcode;
67 : // True iff we need to save the flags for this access.
68 : bool save_flags;
69 : };
70 :
71 : typedef block_graph::BlockGraph BlockGraph;
72 : typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
73 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
74 : typedef MemoryAccessInfo AsanHookMapEntryKey;
75 : // Map of hooks to Asan check access functions.
76 : typedef std::map<AsanHookMapEntryKey, BlockGraph::Reference> AsanHookMap;
77 : typedef std::map<MemoryAccessMode, BlockGraph::Reference> AsanDefaultHookMap;
78 :
79 : // Constructor.
80 : // @param check_access_hooks References to the various check access functions.
81 : // The hooks are assumed to be direct references for COFF images, and
82 : // indirect references for PE images.
83 : explicit AsanBasicBlockTransform(AsanHookMap* check_access_hooks) :
84 : check_access_hooks_(check_access_hooks),
85 : debug_friendly_(false),
86 : dry_run_(false),
87 : instrumentation_happened_(false),
88 : instrumentation_rate_(1.0),
89 : remove_redundant_checks_(false),
90 E : use_liveness_analysis_(false) {
91 E : DCHECK(check_access_hooks != NULL);
92 E : }
93 :
94 : // @name Accessors and mutators.
95 : // @{
96 : bool debug_friendly() const { return debug_friendly_; }
97 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
98 :
99 E : bool use_liveness_analysis() { return use_liveness_analysis_; }
100 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
101 E : use_liveness_analysis_ = use_liveness_analysis;
102 E : }
103 :
104 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
105 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
106 E : remove_redundant_checks_ = remove_redundant_checks;
107 E : }
108 :
109 : // The instrumentation rate must be in the range [0, 1], inclusive.
110 E : double instrumentation_rate() const { return instrumentation_rate_; }
111 : void set_instrumentation_rate(double instrumentation_rate);
112 :
113 : // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
114 : // only signals if any instrumentation would have happened on the block.
115 : // @returns true iff the instrumenter is in dry run mode.
116 E : bool dry_run() const { return dry_run_; }
117 : // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
118 : // only signals if any instrumentation would have happened on the block.
119 : // @param dry_run true iff dry run mode is on.
120 E : void set_dry_run(bool dry_run) { dry_run_ = dry_run; }
121 :
122 : // If at least one instrumentation happened during a transform, or would have
123 : // happened during a dry run transform, this returns true.
124 : // @returns true iff an instrumentation happened (or would have happened, in
125 : // case of a dry run).
126 E : bool instrumentation_happened() const { return instrumentation_happened_; }
127 : // @}
128 :
129 : // The transform name.
130 : static const char kTransformName[];
131 :
132 : // @name BasicBlockSubGraphTransformInterface method.
133 : bool TransformBasicBlockSubGraph(
134 : const TransformPolicyInterface* policy,
135 : BlockGraph* block_graph,
136 : BasicBlockSubGraph* basic_block_subgraph) override;
137 :
138 : protected:
139 : // Instruments the memory accesses in a basic block.
140 : // @param basic_block The basic block to be instrumented.
141 : // @param stack_mode Give some assumptions to the transformation on stack
142 : // frame manipulations inside @p basic_block. The transformation assume a
143 : // standard calling convention, unless specified by this parameter.
144 : // (note: Unsafe blocks may be produced with the compiler flag
145 : // frame-pointer-omission).
146 : // @param image_format The format of the image being instrumented. The details
147 : // of how we invoke the hooks vary depending on this.
148 : // @returns true on success, false otherwise.
149 : bool InstrumentBasicBlock(block_graph::BasicCodeBlock* basic_block,
150 : StackAccessMode stack_mode,
151 : BlockGraph::ImageFormat image_format);
152 :
153 : private:
154 : // Liveness analysis and liveness information for this subgraph.
155 : block_graph::analysis::LivenessAnalysis liveness_;
156 :
157 : // Memory accesses value numbering.
158 : block_graph::analysis::MemoryAccessAnalysis memory_accesses_;
159 :
160 : // The references to the Asan access check import entries.
161 : AsanHookMap* check_access_hooks_;
162 :
163 : // Activate the overwriting of source range for created instructions.
164 : bool debug_friendly_;
165 :
166 : // Instead of instrumenting the basic blocks, run in dry run mode and just
167 : // signal whether there would be an instrumentation in the block.
168 : bool dry_run_;
169 :
170 : // Controls the rate at which reads/writes are instrumented. This is
171 : // implemented using random sampling.
172 : double instrumentation_rate_;
173 :
174 : // If any instrumentation happened during a transform, or would have happened
175 : // during a dry run transform, this member is set to true.
176 : bool instrumentation_happened_;
177 :
178 : // When activated, a redundancy elimination is performed to minimize the
179 : // memory checks added by this transform.
180 : bool remove_redundant_checks_;
181 :
182 : // Set iff we should use the liveness analysis to do smarter instrumentation.
183 : bool use_liveness_analysis_;
184 :
185 : DISALLOW_COPY_AND_ASSIGN(AsanBasicBlockTransform);
186 : };
187 :
188 : // This runs Asan basic block transform in dry run mode and prepares the block
189 : // for hot patching if Asan would instrument it. Doing these two things in a
190 : // single basic block transform avoids running basic block decomposer twice.
191 : class HotPatchingAsanBasicBlockTransform
192 : : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
193 : AsanBasicBlockTransform>,
194 : public block_graph::Filterable {
195 : public:
196 : typedef block_graph::BlockGraph BlockGraph;
197 : typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
198 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
199 :
200 : // Construct a HotPatchingAsanBasicBlockTransform.
201 : // @param asan_bb_transform An Asan basic block transform that will be run
202 : // to check if an instrumentation would happen.
203 : // @pre the transform in the parameter must be in dry run mode.
204 : HotPatchingAsanBasicBlockTransform(
205 : AsanBasicBlockTransform* asan_bb_transform);
206 :
207 : // @name BasicBlockSubGraphTransformInterface method.
208 : bool TransformBasicBlockSubGraph(
209 : const TransformPolicyInterface* policy,
210 : BlockGraph* block_graph,
211 : BasicBlockSubGraph* basic_block_subgraph) override;
212 :
213 : // Check if the block in the subgraph was prepared for hot patching during
214 : // the last run of TransformBasicBlockSubGraph.
215 : // @returns true if the prepared the block for hot patching, false if the
216 : // block needs no Asan instrumentation.
217 E : bool prepared_for_hot_patching() {
218 E : return prepared_for_hot_patching_;
219 E : }
220 :
221 : private:
222 : AsanBasicBlockTransform* asan_bb_transform_;
223 :
224 : bool prepared_for_hot_patching_;
225 :
226 : DISALLOW_COPY_AND_ASSIGN(HotPatchingAsanBasicBlockTransform);
227 : };
228 :
229 : class AsanTransform
230 : : public block_graph::transforms::IterativeTransformImpl<AsanTransform>,
231 : public block_graph::Filterable {
232 : public:
233 : typedef block_graph::BlockGraph BlockGraph;
234 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
235 : typedef AsanBasicBlockTransform::MemoryAccessMode MemoryAccessMode;
236 : typedef std::set<BlockGraph::Block*, BlockGraph::BlockIdLess> BlockSet;
237 :
238 : // Initialize a new AsanTransform instance.
239 : AsanTransform();
240 :
241 : ~AsanTransform();
242 :
243 : // @name IterativeTransformImpl implementation.
244 : // @{
245 : bool PreBlockGraphIteration(const TransformPolicyInterface* policy,
246 : BlockGraph* block_graph,
247 : BlockGraph::Block* header_block);
248 : bool OnBlock(const TransformPolicyInterface* policy,
249 : BlockGraph* block_graph,
250 : BlockGraph::Block* block);
251 : bool PostBlockGraphIteration(const TransformPolicyInterface* policy,
252 : BlockGraph* block_graph,
253 : BlockGraph::Block* header_block);
254 : // @}
255 :
256 : // @name Accessors and mutators.
257 : // @{
258 E : void set_instrument_dll_name(const base::StringPiece& instrument_dll_name) {
259 E : instrument_dll_name.CopyToString(&asan_dll_name_);
260 E : }
261 : // Name of the asan_rtl DLL we import. The |instrument_dll_name_| member is
262 : // empty by default, in that case |kSyzyAsanDll| will be returned if hot
263 : // patching mode is disabled and |kSyzyAsanHpDll| will be returned in hot
264 : // patching mode.
265 : // @returns the name of the runtime library of the instrumentation.
266 : base::StringPiece instrument_dll_name() const;
267 :
268 E : bool debug_friendly() const { return debug_friendly_; }
269 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
270 :
271 E : bool use_interceptors() const { return use_interceptors_; }
272 E : void set_use_interceptors(bool use_interceptors) {
273 E : use_interceptors_ = use_interceptors;
274 E : }
275 :
276 E : bool use_liveness_analysis() const { return use_liveness_analysis_; }
277 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
278 E : use_liveness_analysis_ = use_liveness_analysis;
279 E : }
280 :
281 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
282 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
283 E : remove_redundant_checks_ = remove_redundant_checks;
284 E : }
285 :
286 : // The instrumentation rate must be in the range [0, 1], inclusive.
287 E : double instrumentation_rate() const { return instrumentation_rate_; }
288 : void set_instrumentation_rate(double instrumentation_rate);
289 :
290 : // Asan RTL parameters.
291 E : const common::InflatedAsanParameters* asan_parameters() const {
292 E : return asan_parameters_;
293 E : }
294 : void set_asan_parameters(
295 E : const common::InflatedAsanParameters* asan_parameters) {
296 E : asan_parameters_ = asan_parameters;
297 E : }
298 : // @}
299 :
300 : // Checks if the transform is in hot patching mode.
301 : // @returns true iff in hot patching mode.
302 E : bool hot_patching() const {
303 E : return hot_patching_;
304 E : }
305 : // If this flag is true, running the transformation prepares the module to
306 : // be used by the hot patching Asan runtime.
307 : // @param hot_patching The new value of the flag.
308 E : void set_hot_patching(bool hot_patching) {
309 E : hot_patching_ = hot_patching;
310 E : }
311 :
312 : // The name of the DLL that is imported by default if hot patching mode is
313 : // inactive.
314 : static const char kSyzyAsanDll[];
315 :
316 : // The name of the DLL that is imported by default in hot patching mode.
317 : static const char kSyzyAsanHpDll[];
318 :
319 : // The transform name.
320 : static const char kTransformName[];
321 :
322 : // The hooks stub name.
323 : static const char kAsanHookStubName[];
324 :
325 : protected:
326 : // PreBlockGraphIteration uses this to find the block of the _heap_init
327 : // function and the data block of _crtheap. This information is used by
328 : // PatchCRTHeapInitialization. Also, the block of _heap_init is skipped by
329 : // OnBlock.
330 : // Calling this initializes heap_init_block_ and crtheap_block_ members.
331 : // @param block_graph The block graph to be searched.
332 : // @pre Both heap_init_block_ and crtheap_block_ must be nullptr.
333 : // @note If either heap_init_block_ and crtheap_block_ is not found, both are
334 : // set to nullptr.
335 : void FindHeapInitAndCrtHeapBlocks(BlockGraph* block_graph);
336 :
337 : // Decides if we should skip a Block in OnBlock. A block is skipped if
338 : // either
339 : // - it is the block of _heap_init,
340 : // - it is in the static_intercepted_blocks_ set,
341 : // - it is not safe to BB-decompose.
342 : // @param policy The policy object that tells if a block is safe to
343 : // BB-decompose.
344 : // @param block The block to examine.
345 : // @returns true iff the block should be skipped.
346 : bool ShouldSkipBlock(const TransformPolicyInterface* policy,
347 : BlockGraph::Block* block);
348 :
349 : // @name PE-specific methods.
350 : // @{
351 : // Finds statically linked functions that need to be intercepted. Called in
352 : // PreBlockGraphTransform. Fills the static_intercepted_blocks_ set.
353 : // Blocks in this set are skipped in OnBlock and intercepted in
354 : // PeInterceptFunctions.
355 : // @param intercepts The Asan intercepts.
356 : // @param block_graph The block graph to search in.
357 : void PeFindStaticallyLinkedFunctionsToIntercept(
358 : const AsanIntercept* intercepts,
359 : BlockGraph* block_graph);
360 :
361 : // Invoked when instrumenting a PE image. Intercepts all relevant import
362 : // and statically linked functions found in the image. The intercepts to be
363 : // used are exposed for unittesting.
364 : bool PeInterceptFunctions(const AsanIntercept* intercepts,
365 : const TransformPolicyInterface* policy,
366 : BlockGraph* block_graph,
367 : BlockGraph::Block* header_block);
368 :
369 : // Injects runtime parameters into the image.
370 : bool PeInjectAsanParameters(const TransformPolicyInterface* policy,
371 : BlockGraph* block_graph,
372 : BlockGraph::Block* header_block);
373 : // @}
374 :
375 : // @name COFF-specific methods.
376 : // @{
377 : // Invoked when instrumenting a COFF image. Intercepts all relevant functions
378 : // via symbol renaming, redirecting to Asan instrumented versions. The
379 : // intercepts to be used are exposed for unittesting.
380 : bool CoffInterceptFunctions(const AsanIntercept* intercepts,
381 : const TransformPolicyInterface* policy,
382 : BlockGraph* block_graph,
383 : BlockGraph::Block* header_block);
384 : // @}
385 :
386 : // Name of the asan_rtl DLL we import. Do not access this directly, use the
387 : // instrument_dll_name() getter that provides default values.
388 : std::string asan_dll_name_;
389 :
390 : // Activate the overwriting of source range for created instructions.
391 : bool debug_friendly_;
392 :
393 : // Set iff we should use the liveness analysis to do smarter instrumentation.
394 : bool use_liveness_analysis_;
395 :
396 : // When activated, a redundancy elimination is performed to minimize the
397 : // memory checks added by this transform.
398 : bool remove_redundant_checks_;
399 :
400 : // Set iff we should use the functions interceptors.
401 : bool use_interceptors_;
402 :
403 : // Controls the rate at which reads/writes are instrumented. This is
404 : // implemented using random sampling.
405 : double instrumentation_rate_;
406 :
407 : // Asan RTL parameters that will be injected into the instrumented image.
408 : // These will be found by the RTL and used to control its behaviour. Allows
409 : // for setting parameters at instrumentation time that vary from the defaults.
410 : // These can still be overridden by configuring the RTL via an environment
411 : // variable.
412 : const common::InflatedAsanParameters* asan_parameters_;
413 :
414 : // References to the different Asan check access import entries. Valid after
415 : // successful PreBlockGraphIteration.
416 : AsanBasicBlockTransform::AsanHookMap check_access_hooks_ref_;
417 :
418 : // Block containing any injected runtime parameters. Valid in PE mode after
419 : // a successful PostBlockGraphIteration. This is a unittesting seam.
420 : block_graph::BlockGraph::Block* asan_parameters_block_;
421 :
422 : // Vector of CRT heap initialization blocks. These are determined during
423 : // PreBlockGraphIteration.
424 : std::vector<BlockGraph::Block*> heap_init_blocks_;
425 :
426 : // Statically linked functions that need to be intercepted. Populated by
427 : // PeFindStaticallyLinkedFunctionsToIntercept. Block in this set are skipped
428 : // in OnBlock and intercepted in PeInterceptFunctions.
429 : // This is a set because OnBlock needs fast lookup. We sort by the BlockID
430 : // to have a consistent output in PeInterceptFunctions.
431 : BlockSet static_intercepted_blocks_;
432 :
433 : // If this flag is true, running the transformation prepares the module to
434 : // be used by the hot patching Asan runtime.
435 : bool hot_patching_;
436 :
437 : // In hot patching mode, this vector is used to collect the blocks prepared
438 : // for hot patching in the OnBlock method and insert them to the hot patching
439 : // metadata stream in the PostBlockGraphIteration.
440 : std::vector<BlockGraph::Block*> hot_patched_blocks_;
441 :
442 : private:
443 : DISALLOW_COPY_AND_ASSIGN(AsanTransform);
444 : };
445 :
446 : bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
447 : const AsanBasicBlockTransform::MemoryAccessInfo& right);
448 :
449 : } // namespace transforms
450 : } // namespace instrument
451 :
452 : #endif // SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
|