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/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/pe/transforms/pe_add_imports_transform.h"
33 :
34 : namespace instrument {
35 : namespace transforms {
36 :
37 : // This class implements the transformation applied to each basic block.
38 : class AsanBasicBlockTransform
39 : : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
40 : AsanBasicBlockTransform>,
41 : public block_graph::Filterable {
42 : public:
43 : // Represent the different kind of access to the memory.
44 : enum MemoryAccessMode {
45 : kNoAccess,
46 : kReadAccess,
47 : kWriteAccess,
48 : kInstrAccess,
49 : kRepzAccess,
50 : kRepnzAccess,
51 : };
52 :
53 : enum StackAccessMode {
54 : kUnsafeStackAccess,
55 : kSafeStackAccess,
56 : };
57 :
58 : // Contains memory access information.
59 : struct MemoryAccessInfo {
60 : MemoryAccessMode mode;
61 : uint8_t size;
62 : uint16_t opcode;
63 : // True iff we need to save the flags for this access.
64 : bool save_flags;
65 : };
66 :
67 : typedef block_graph::BlockGraph BlockGraph;
68 : typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
69 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
70 : typedef MemoryAccessInfo AsanHookMapEntryKey;
71 : // Map of hooks to asan check access functions.
72 : typedef std::map<AsanHookMapEntryKey, BlockGraph::Reference> AsanHookMap;
73 : typedef std::map<MemoryAccessMode, BlockGraph::Reference> AsanDefaultHookMap;
74 :
75 : // Constructor.
76 : // @param hooks_read_access a reference to the read access check import entry.
77 : // @param hooks_write_access a reference to the write access check import
78 : // entry.
79 : explicit AsanBasicBlockTransform(AsanHookMap* check_access_hooks) :
80 : check_access_hooks_(check_access_hooks),
81 : debug_friendly_(false),
82 : use_liveness_analysis_(false),
83 E : remove_redundant_checks_(false) {
84 E : DCHECK(check_access_hooks != NULL);
85 E : }
86 :
87 : // @name Accessors.
88 : // @{
89 : bool debug_friendly() const { return debug_friendly_; }
90 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
91 :
92 E : bool use_liveness_analysis() { return use_liveness_analysis_; }
93 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
94 E : use_liveness_analysis_ = use_liveness_analysis;
95 E : }
96 :
97 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
98 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
99 E : remove_redundant_checks_ = remove_redundant_checks;
100 E : }
101 :
102 : // @}
103 :
104 : // The transform name.
105 : static const char kTransformName[];
106 :
107 : protected:
108 : // @name BasicBlockSubGraphTransformInterface method.
109 : virtual bool TransformBasicBlockSubGraph(
110 : const TransformPolicyInterface* policy,
111 : BlockGraph* block_graph,
112 : BasicBlockSubGraph* basic_block_subgraph) OVERRIDE;
113 :
114 : // Instruments the memory accesses in a basic block.
115 : // @param basic_block The basic block to be instrumented.
116 : // @param stack_mode Give some assumptions to the transformation on stack
117 : // frame manipulations inside @p basic_block. The transformation assume a
118 : // standard calling convention, unless specified by this parameter.
119 : // (note: Unsafe blocks may be produced with the compiler flag
120 : // frame-pointer-omission).
121 : // @returns true on success, false otherwise.
122 : bool InstrumentBasicBlock(block_graph::BasicCodeBlock* basic_block,
123 : StackAccessMode stack_mode);
124 :
125 : private:
126 : // Liveness analysis and liveness information for this subgraph.
127 : block_graph::analysis::LivenessAnalysis liveness_;
128 :
129 : // Memory accesses value numbering.
130 : block_graph::analysis::MemoryAccessAnalysis memory_accesses_;
131 :
132 : // The references to the Asan access check import entries.
133 : AsanHookMap* check_access_hooks_;
134 :
135 : // Activate the overwriting of source range for created instructions.
136 : bool debug_friendly_;
137 :
138 : // Set iff we should use the liveness analysis to do smarter instrumentation.
139 : bool use_liveness_analysis_;
140 :
141 : // When activated, a redundancy elimination is performed to minimize the
142 : // memory checks added by this transform.
143 : bool remove_redundant_checks_;
144 :
145 : DISALLOW_COPY_AND_ASSIGN(AsanBasicBlockTransform);
146 : };
147 :
148 : class AsanTransform
149 : : public block_graph::transforms::IterativeTransformImpl<AsanTransform>,
150 : public block_graph::Filterable {
151 : public:
152 : typedef block_graph::BlockGraph BlockGraph;
153 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
154 : typedef AsanBasicBlockTransform::MemoryAccessInfo MemoryAccessInfo;
155 : typedef AsanBasicBlockTransform::MemoryAccessMode MemoryAccessMode;
156 :
157 : // Initialize a new AsanTransform instance.
158 : AsanTransform();
159 :
160 : // @name IterativeTransformImpl implementation.
161 : // @{
162 : bool PreBlockGraphIteration(const TransformPolicyInterface* policy,
163 : BlockGraph* block_graph,
164 : BlockGraph::Block* header_block);
165 : bool OnBlock(const TransformPolicyInterface* policy,
166 : BlockGraph* block_graph,
167 : BlockGraph::Block* block);
168 : bool PostBlockGraphIteration(const TransformPolicyInterface* policy,
169 : BlockGraph* block_graph,
170 : BlockGraph::Block* header_block);
171 : // @}
172 :
173 : // @name Accessors.
174 : // @{
175 E : void set_instrument_dll_name(const base::StringPiece& instrument_dll_name) {
176 E : instrument_dll_name.CopyToString(&asan_dll_name_);
177 E : }
178 E : const char* instrument_dll_name() const {
179 E : return asan_dll_name_.c_str();
180 E : }
181 :
182 E : bool debug_friendly() const { return debug_friendly_; }
183 E : void set_debug_friendly(bool flag) { debug_friendly_ = flag; }
184 :
185 E : bool use_interceptors() const { return use_interceptors_; }
186 E : void set_use_interceptors(bool use_interceptors) {
187 E : use_interceptors_ = use_interceptors;
188 E : }
189 :
190 E : bool use_liveness_analysis() const { return use_liveness_analysis_; }
191 E : void set_use_liveness_analysis(bool use_liveness_analysis) {
192 E : use_liveness_analysis_ = use_liveness_analysis;
193 E : }
194 :
195 E : bool remove_redundant_checks() const { return remove_redundant_checks_; }
196 E : void set_remove_redundant_checks(bool remove_redundant_checks) {
197 E : remove_redundant_checks_ = remove_redundant_checks;
198 E : }
199 :
200 : // @}
201 :
202 : // The name of the DLL that is imported by default.
203 : static const char kSyzyAsanDll[];
204 :
205 : // The transform name.
206 : static const char kTransformName[];
207 :
208 : // The hooks stub name.
209 : static const char kAsanHookStubName[];
210 :
211 : protected:
212 : // A structure containing the information that we need to intercept a
213 : // function.
214 : struct FunctionInterceptionInfo {
215 : // The function's block.
216 : BlockGraph::Block* function_block;
217 : // The index for the Asan hook for this function.
218 : size_t asan_symbol_index;
219 :
220 E : FunctionInterceptionInfo() : function_block(NULL), asan_symbol_index(~0U) {
221 E : }
222 : };
223 :
224 : typedef pe::transforms::ImportedModule ImportedModule;
225 : typedef std::set<std::string> FunctionInterceptionSet;
226 : typedef std::map<std::string,
227 : FunctionInterceptionInfo> FunctionInterceptionInfoMap;
228 :
229 : // Intercept the calls to the functions for which we want to check the
230 : // arguments (i.e. the CRT functions written in assembly) and thunk them. The
231 : // thunk will defer the call to the original function to its instrumented
232 : // version in asan_rtl.
233 : // @param import_module The module for which the imports should be added.
234 : // @param policy The policy object restricting how the transform is applied.
235 : // @param block_graph The block-graph to modify.
236 : // @param header_block The block containing the module's DOS header of this
237 : // block-graph.
238 : // @param functions_set The list of the function that we want to intercept.
239 : // @returns true on success, false on error.
240 : bool InterceptFunctions(ImportedModule* import_module,
241 : const TransformPolicyInterface* policy,
242 : BlockGraph* block_graph,
243 : BlockGraph::Block* header_block,
244 : const FunctionInterceptionSet& functions_set);
245 :
246 : // Name of the asan_rtl DLL we import. Defaults to "syzyasan_rtl.dll".
247 : std::string asan_dll_name_;
248 :
249 : // Activate the overwriting of source range for created instructions.
250 : bool debug_friendly_;
251 :
252 : // Set iff we should use the liveness analysis to do smarter instrumentation.
253 : bool use_liveness_analysis_;
254 :
255 : // When activated, a redundancy elimination is performed to minimize the
256 : // memory checks added by this transform.
257 : bool remove_redundant_checks_;
258 :
259 : // Set iff we should use the functions interceptors.
260 : bool use_interceptors_;
261 :
262 : // References to the different asan check access import entries. Valid after
263 : // successful PreBlockGraphIteration.
264 : AsanBasicBlockTransform::AsanHookMap check_access_hooks_ref_;
265 :
266 : private:
267 : DISALLOW_COPY_AND_ASSIGN(AsanTransform);
268 : };
269 :
270 : bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
271 : const AsanBasicBlockTransform::MemoryAccessInfo& right);
272 :
273 : } // namespace transforms
274 : } // namespace instrument
275 :
276 : #endif // SYZYGY_INSTRUMENT_TRANSFORMS_ASAN_TRANSFORM_H_
|