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 :
25 : #include "base/strings/string_piece.h"
26 : #include "syzygy/block_graph/filterable.h"
27 : #include "syzygy/block_graph/iterate.h"
28 : #include "syzygy/block_graph/analysis/liveness_analysis.h"
29 : #include "syzygy/block_graph/analysis/memory_access_analysis.h"
30 : #include "syzygy/block_graph/transforms/iterative_transform.h"
31 : #include "syzygy/block_graph/transforms/named_transform.h"
32 : #include "syzygy/common/asan_parameters.h"
33 : #include "syzygy/instrument/transforms/asan_interceptor_filter.h"
34 : #include "syzygy/instrument/transforms/asan_intercepts.h"
35 :
36 : namespace instrument {
37 : namespace transforms {
38 :
39 : // This class implements the transformation applied to each basic block.
40 : class AsanBasicBlockTransform
41 : : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
42 : AsanBasicBlockTransform>,
43 : public block_graph::Filterable {
44 : public:
45 : // Represent the different kind of access to the memory.
46 : enum MemoryAccessMode {
47 : kNoAccess,
48 : kReadAccess,
49 : kWriteAccess,
50 : kInstrAccess,
51 : kRepzAccess,
52 : kRepnzAccess,
53 : };
54 :
55 : enum StackAccessMode {
56 : kUnsafeStackAccess,
57 : kSafeStackAccess,
58 : };
59 :
60 : // Contains memory access information.
61 : struct MemoryAccessInfo {
62 : MemoryAccessMode mode;
63 : uint8_t size;
64 : uint16_t opcode;
65 : // True iff we need to save the flags for this access.
66 : bool save_flags;
67 : };
68 :
69 : typedef block_graph::BlockGraph BlockGraph;
70 : typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
71 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
72 : typedef MemoryAccessInfo AsanHookMapEntryKey;
73 : // Map of hooks to Asan check access functions.
74 : typedef std::map<AsanHookMapEntryKey, BlockGraph::Reference> AsanHookMap;
75 : typedef std::map<MemoryAccessMode, BlockGraph::Reference> AsanDefaultHookMap;
76 :
77 : // Constructor.
78 : // @param check_access_hooks References to the various check access functions.
79 : // The hooks are assumed to be direct references for COFF images, and
80 : // indirect references for PE images.
81 : explicit AsanBasicBlockTransform(AsanHookMap* check_access_hooks) :
82 : check_access_hooks_(check_access_hooks),
83 : debug_friendly_(false),
84 : dry_run_(false),
85 : instrumentation_happened_(false),
86 : instrumentation_rate_(1.0),
87 : remove_redundant_checks_(false),
88 E : use_liveness_analysis_(false) {
89 E : DCHECK(check_access_hooks != NULL);
90 E : }
91 :
92 : // @name Accessors and mutators.
93 : // @{
94 : bool debug_friendly() const { return debug_friendly_; }
95 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
96 :
97 E : bool use_liveness_analysis() { return use_liveness_analysis_; }
98 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
99 E : use_liveness_analysis_ = use_liveness_analysis;
100 E : }
101 :
102 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
103 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
104 E : remove_redundant_checks_ = remove_redundant_checks;
105 E : }
106 :
107 : // The instrumentation rate must be in the range [0, 1], inclusive.
108 E : double instrumentation_rate() const { return instrumentation_rate_; }
109 : void set_instrumentation_rate(double instrumentation_rate);
110 :
111 : // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
112 : // only signals if any instrumentation would have happened on the block.
113 : // @returns true iff the instrumenter is in dry run mode.
114 E : bool dry_run() const { return dry_run_; }
115 : // Instead of instrumenting the basic blocks, in dry run mode the instrumenter
116 : // only signals if any instrumentation would have happened on the block.
117 : // @param dry_run true iff dry run mode is on.
118 E : void set_dry_run(bool dry_run) { dry_run_ = dry_run; }
119 :
120 : // If at least one instrumentation happened during a transform, or would have
121 : // happened during a dry run transform, this returns true.
122 : // @returns true iff an instrumentation happened (or would have happened, in
123 : // case of a dry run).
124 E : bool instrumentation_happened() const { return instrumentation_happened_; }
125 : // @}
126 :
127 : // The transform name.
128 : static const char kTransformName[];
129 :
130 : protected:
131 : // @name BasicBlockSubGraphTransformInterface method.
132 : virtual bool TransformBasicBlockSubGraph(
133 : const TransformPolicyInterface* policy,
134 : BlockGraph* block_graph,
135 : BasicBlockSubGraph* basic_block_subgraph) OVERRIDE;
136 :
137 : // Instruments the memory accesses in a basic block.
138 : // @param basic_block The basic block to be instrumented.
139 : // @param stack_mode Give some assumptions to the transformation on stack
140 : // frame manipulations inside @p basic_block. The transformation assume a
141 : // standard calling convention, unless specified by this parameter.
142 : // (note: Unsafe blocks may be produced with the compiler flag
143 : // frame-pointer-omission).
144 : // @param image_format The format of the image being instrumented. The details
145 : // of how we invoke the hooks vary depending on this.
146 : // @returns true on success, false otherwise.
147 : bool InstrumentBasicBlock(block_graph::BasicCodeBlock* basic_block,
148 : StackAccessMode stack_mode,
149 : BlockGraph::ImageFormat image_format);
150 :
151 : private:
152 : // Liveness analysis and liveness information for this subgraph.
153 : block_graph::analysis::LivenessAnalysis liveness_;
154 :
155 : // Memory accesses value numbering.
156 : block_graph::analysis::MemoryAccessAnalysis memory_accesses_;
157 :
158 : // The references to the Asan access check import entries.
159 : AsanHookMap* check_access_hooks_;
160 :
161 : // Activate the overwriting of source range for created instructions.
162 : bool debug_friendly_;
163 :
164 : // Instead of instrumenting the basic blocks, run in dry run mode and just
165 : // signal whether there would be an instrumenation in the block.
166 : bool dry_run_;
167 :
168 : // Controls the rate at which reads/writes are instrumented. This is
169 : // implemented using random sampling.
170 : double instrumentation_rate_;
171 :
172 : // If any instrumentation happened during a transform, or would have happened
173 : // during a dry run transform, this member is set to true.
174 : bool instrumentation_happened_;
175 :
176 : // When activated, a redundancy elimination is performed to minimize the
177 : // memory checks added by this transform.
178 : bool remove_redundant_checks_;
179 :
180 : // Set iff we should use the liveness analysis to do smarter instrumentation.
181 : bool use_liveness_analysis_;
182 :
183 : DISALLOW_COPY_AND_ASSIGN(AsanBasicBlockTransform);
184 : };
185 :
186 : class AsanTransform
187 : : public block_graph::transforms::IterativeTransformImpl<AsanTransform>,
188 : public block_graph::Filterable {
189 : public:
190 : typedef block_graph::BlockGraph BlockGraph;
191 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
192 : typedef AsanBasicBlockTransform::MemoryAccessInfo MemoryAccessInfo;
193 : typedef AsanBasicBlockTransform::MemoryAccessMode MemoryAccessMode;
194 :
195 : // Initialize a new AsanTransform instance.
196 : AsanTransform();
197 :
198 : // @name IterativeTransformImpl implementation.
199 : // @{
200 : bool PreBlockGraphIteration(const TransformPolicyInterface* policy,
201 : BlockGraph* block_graph,
202 : BlockGraph::Block* header_block);
203 : bool OnBlock(const TransformPolicyInterface* policy,
204 : BlockGraph* block_graph,
205 : BlockGraph::Block* block);
206 : bool PostBlockGraphIteration(const TransformPolicyInterface* policy,
207 : BlockGraph* block_graph,
208 : BlockGraph::Block* header_block);
209 : // @}
210 :
211 : // @name Accessors and mutators.
212 : // @{
213 E : void set_instrument_dll_name(const base::StringPiece& instrument_dll_name) {
214 E : instrument_dll_name.CopyToString(&asan_dll_name_);
215 E : }
216 E : const char* instrument_dll_name() const {
217 E : return asan_dll_name_.c_str();
218 E : }
219 :
220 E : bool debug_friendly() const { return debug_friendly_; }
221 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
222 :
223 E : bool use_interceptors() const { return use_interceptors_; }
224 E : void set_use_interceptors(bool use_interceptors) {
225 E : use_interceptors_ = use_interceptors;
226 E : }
227 :
228 E : bool use_liveness_analysis() const { return use_liveness_analysis_; }
229 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
230 E : use_liveness_analysis_ = use_liveness_analysis;
231 E : }
232 :
233 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
234 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
235 E : remove_redundant_checks_ = remove_redundant_checks;
236 E : }
237 :
238 : // The instrumentation rate must be in the range [0, 1], inclusive.
239 E : double instrumentation_rate() const { return instrumentation_rate_; }
240 : void set_instrumentation_rate(double instrumentation_rate);
241 :
242 : // Asan RTL parameters.
243 E : const common::InflatedAsanParameters* asan_parameters() const {
244 E : return asan_parameters_;
245 E : }
246 : void set_asan_parameters(
247 E : const common::InflatedAsanParameters* asan_parameters) {
248 E : asan_parameters_ = asan_parameters;
249 E : }
250 : // @}
251 :
252 : // The name of the DLL that is imported by default.
253 : static const char kSyzyAsanDll[];
254 :
255 : // The transform name.
256 : static const char kTransformName[];
257 :
258 : // The hooks stub name.
259 : static const char kAsanHookStubName[];
260 :
261 : protected:
262 : // @name PE-specific methods.
263 : // @{
264 : // Invoked when instrumenting a PE image. Intercepts all relevant import
265 : // and statically linked functions found in the image. The intercepts to be
266 : // used are exposed for unittesting.
267 : bool PeInterceptFunctions(const AsanIntercept* intercepts,
268 : const TransformPolicyInterface* policy,
269 : BlockGraph* block_graph,
270 : BlockGraph::Block* header_block);
271 :
272 : // Injects runtime parameters into the image.
273 : bool PeInjectAsanParameters(const TransformPolicyInterface* policy,
274 : BlockGraph* block_graph,
275 : BlockGraph::Block* header_block);
276 : // @}
277 :
278 : // @name COFF-specific methods.
279 : // @{
280 : // Invoked when instrumenting a COFF image. Intercepts all relevant functions
281 : // via symbol renaming, redirecting to Asan instrumented versions. The
282 : // intercepts to be used are exposed for unittesting.
283 : bool CoffInterceptFunctions(const AsanIntercept* intercepts,
284 : const TransformPolicyInterface* policy,
285 : BlockGraph* block_graph,
286 : BlockGraph::Block* header_block);
287 : // @}
288 :
289 : // Name of the asan_rtl DLL we import. Defaults to "syzyasan_rtl.dll".
290 : std::string asan_dll_name_;
291 :
292 : // Activate the overwriting of source range for created instructions.
293 : bool debug_friendly_;
294 :
295 : // Set iff we should use the liveness analysis to do smarter instrumentation.
296 : bool use_liveness_analysis_;
297 :
298 : // When activated, a redundancy elimination is performed to minimize the
299 : // memory checks added by this transform.
300 : bool remove_redundant_checks_;
301 :
302 : // Set iff we should use the functions interceptors.
303 : bool use_interceptors_;
304 :
305 : // Controls the rate at which reads/writes are instrumented. This is
306 : // implemented using random sampling.
307 : double instrumentation_rate_;
308 :
309 : // Asan RTL parameters that will be injected into the instrumented image.
310 : // These will be found by the RTL and used to control its behaviour. Allows
311 : // for setting parameters at instrumentation time that vary from the defaults.
312 : // These can still be overridden by configuring the RTL via an environment
313 : // variable.
314 : const common::InflatedAsanParameters* asan_parameters_;
315 :
316 : // References to the different Asan check access import entries. Valid after
317 : // successful PreBlockGraphIteration.
318 : AsanBasicBlockTransform::AsanHookMap check_access_hooks_ref_;
319 :
320 : // Block containing any injected runtime parameters. Valid in PE mode after
321 : // a successful PostBlockGraphIteration. This is a unittesting seam.
322 : block_graph::BlockGraph::Block* asan_parameters_block_;
323 :
324 : private:
325 : DISALLOW_COPY_AND_ASSIGN(AsanTransform);
326 : };
327 :
328 : bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
329 : const AsanBasicBlockTransform::MemoryAccessInfo& right);
330 :
331 : } // namespace transforms
332 : } // namespace instrument
333 :
334 : #endif // SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
|