1 : // Copyright 2013 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 : #include "syzygy/instrument/instrumenters/asan_instrumenter.h"
16 :
17 : #include <algorithm>
18 :
19 : #include "base/file_util.h"
20 : #include "base/logging.h"
21 : #include "syzygy/application/application.h"
22 : #include "syzygy/instrument/transforms/allocation_filter_transform.h"
23 :
24 : namespace {
25 : using instrument::transforms::AllocationFilterTransform;
26 : }
27 :
28 : namespace instrument {
29 : namespace instrumenters {
30 :
31 : const char AsanInstrumenter::kAgentDllAsan[] = "syzyasan_rtl.dll";
32 :
33 : AsanInstrumenter::AsanInstrumenter()
34 : : use_interceptors_(true),
35 : remove_redundant_checks_(true),
36 : use_liveness_analysis_(true),
37 : instrumentation_rate_(1.0),
38 E : asan_rtl_options_(false) {
39 E : agent_dll_ = kAgentDllAsan;
40 E : }
41 :
42 E : bool AsanInstrumenter::ImageFormatIsSupported(ImageFormat image_format) {
43 : if (image_format == BlockGraph::PE_IMAGE ||
44 E : image_format == BlockGraph::COFF_IMAGE) {
45 E : return true;
46 : }
47 i : return false;
48 E : }
49 :
50 E : bool AsanInstrumenter::InstrumentImpl() {
51 : // Parse the filter if one was provided.
52 E : scoped_ptr<pe::ImageFilter> filter;
53 E : if (!filter_path_.empty()) {
54 E : filter.reset(new pe::ImageFilter());
55 E : if (!filter->LoadFromJSON(filter_path_)) {
56 i : LOG(ERROR) << "Failed to parse filter file: " << filter_path_.value();
57 i : return false;
58 : }
59 :
60 : // Ensure it is for the input module.
61 E : if (!filter->IsForModule(input_image_path_)) {
62 E : LOG(ERROR) << "Filter does not match the input module.";
63 E : return false;
64 : }
65 : }
66 :
67 E : asan_transform_.reset(new instrument::transforms::AsanTransform());
68 E : asan_transform_->set_instrument_dll_name(agent_dll_);
69 E : asan_transform_->set_use_interceptors(use_interceptors_);
70 E : asan_transform_->set_use_liveness_analysis(use_liveness_analysis_);
71 E : asan_transform_->set_remove_redundant_checks(remove_redundant_checks_);
72 E : asan_transform_->set_instrumentation_rate(instrumentation_rate_);
73 :
74 : // Set up the filter if one was provided.
75 E : if (filter.get()) {
76 E : filter_.reset(filter.release());
77 E : asan_transform_->set_filter(&filter_->filter);
78 : }
79 :
80 : // Set overwrite source range flag in the Asan transform. The Asan
81 : // transformation will overwrite the source range of created instructions to
82 : // the source range of corresponding instrumented instructions.
83 E : asan_transform_->set_debug_friendly(debug_friendly_);
84 :
85 : // If RTL options were provided then pass them to the transform.
86 E : if (asan_rtl_options_)
87 E : asan_transform_->set_asan_parameters(&asan_params_);
88 :
89 E : if (!relinker_->AppendTransform(asan_transform_.get()))
90 i : return false;
91 :
92 : // Append the AllocationFilter transform if necessary.
93 E : if (af_transform_.get() != nullptr) {
94 E : if (!relinker_->AppendTransform(af_transform_.get()))
95 i : return false;
96 : }
97 :
98 E : return true;
99 E : }
100 :
101 : bool AsanInstrumenter::ParseAdditionalCommandLineArguments(
102 E : const CommandLine* command_line) {
103 : // Parse the additional command line arguments.
104 E : filter_path_ = command_line->GetSwitchValuePath("filter");
105 E : use_liveness_analysis_ = !command_line->HasSwitch("no-liveness-analysis");
106 E : remove_redundant_checks_ = !command_line->HasSwitch("no-redundancy-analysis");
107 E : use_interceptors_ = !command_line->HasSwitch("no-interceptors");
108 :
109 : // Parse the instrumentation rate if one has been provided.
110 : static const char kInstrumentationRate[] = "instrumentation-rate";
111 E : if (command_line->HasSwitch(kInstrumentationRate)) {
112 E : std::string s = command_line->GetSwitchValueASCII(kInstrumentationRate);
113 E : double d = 0;
114 E : if (!base::StringToDouble(s, &d)) {
115 E : LOG(ERROR) << "Failed to parse floating point value: " << s;
116 E : return false;
117 : }
118 : // Cap the rate to the range of valid values [0, 1].
119 E : instrumentation_rate_ = std::max(0.0, std::min(1.0, d));
120 E : }
121 :
122 : // Parse Asan RTL options if present.
123 : static const char kAsanRtlOptions[] = "asan-rtl-options";
124 E : if (asan_rtl_options_ = command_line->HasSwitch(kAsanRtlOptions)) {
125 E : std::wstring options = command_line->GetSwitchValueNative(kAsanRtlOptions);
126 E : common::SetDefaultAsanParameters(&asan_params_);
127 E : if (!common::ParseAsanParameters(options, &asan_params_))
128 E : return false;
129 E : }
130 :
131 : // Parse the allocation-filter flag.
132 : static const char kAsanAllocationFilter[] = "allocation-filter-config-file";
133 : allocation_filter_config_file_path_ = command_line->GetSwitchValuePath(
134 E : kAsanAllocationFilter);
135 :
136 : // Setup the AllocationFilter transform if a configuration file was specified.
137 E : if (!allocation_filter_config_file_path_.empty()) {
138 E : std::string json_string;
139 E : AllocationFilterTransform::FunctionNameOffsetMap target_calls;
140 : if (!AllocationFilterTransform::ReadFromJSON(
141 E : allocation_filter_config_file_path_, &target_calls)) {
142 E : LOG(ERROR) << "Failed to parse allocation-filter configuration file: "
143 : << allocation_filter_config_file_path_.value();
144 E : return false;
145 : }
146 :
147 E : if (!target_calls.empty()) {
148 : // Setup the allocation-filter transform.
149 E : af_transform_.reset(new AllocationFilterTransform(target_calls));
150 :
151 : // Set overwrite source range flag in the AllocationFilter transform.
152 : // It will overwrite the source range of created instructions to the
153 : // source range of corresponding instrumented instructions. The
154 : // AllocationFilter transform shares the Asan flag.
155 E : af_transform_->set_debug_friendly(debug_friendly_);
156 : }
157 E : }
158 :
159 E : return true;
160 E : }
161 :
162 : } // namespace instrumenters
163 : } // namespace instrument
|