blob: 14548cea90417afe6dbe3d68a8c0b6e2640f9518 [file] [log] [blame]
Bharadwaj Kalandhabhatta0bb40312017-06-01 10:47:00 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "dex_file_tracking_registrar.h"
18
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -070019#include <deque>
20#include <tuple>
21
Bharadwaj Kalandhabhatta0bb40312017-06-01 10:47:00 -070022// For dex tracking through poisoning. Note: Requires forcing sanitization. This is the reason for
23// the ifdefs and early include.
24#ifdef ART_DEX_FILE_ACCESS_TRACKING
25#ifndef ART_ENABLE_ADDRESS_SANITIZER
26#define ART_ENABLE_ADDRESS_SANITIZER
27#endif
28#endif
29#include "base/memory_tool.h"
30
31#include "base/logging.h"
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -070032#include "dex_file-inl.h"
Bharadwaj Kalandhabhatta0bb40312017-06-01 10:47:00 -070033
34namespace art {
35namespace dex {
36namespace tracking {
37
38// If true, poison dex files to track accesses.
39static constexpr bool kDexFileAccessTracking =
40#ifdef ART_DEX_FILE_ACCESS_TRACKING
41 true;
42#else
43 false;
44#endif
45
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -070046// The following are configurations of poisoning certain sections of a Dex File.
47// More will be added
48enum DexTrackingType {
49 // Poisons all of a Dex File when set.
50 kWholeDexTracking,
51 // Poisons all Code Items of a Dex File when set.
52 kCodeItemTracking,
53 // Poisons all subsections of a Code Item, except the Insns bytecode array
54 // section, when set for all Code Items in a Dex File.
55 kCodeItemNonInsnsTracking,
56 // Poisons all subsections of a Code Item, except the Insns bytecode array
57 // section, when set for all Code Items in a Dex File.
58 // Additionally unpoisons the entire Code Item when method is a class
59 // initializer.
60 kCodeItemNonInsnsNoClinitTracking,
61 // Poisons based on a custom tracking system which can be specified in
62 // SetDexSections
63 kCustomTracking,
64};
65
66// Intended for local changes only.
67// Represents the current configuration being run.
68static constexpr DexTrackingType kCurrentTrackingSystem = kWholeDexTracking;
69
70// Intended for local changes only.
71void DexFileTrackingRegistrar::SetDexSections() {
72 if (kDexFileAccessTracking || dex_file_ != nullptr) {
73 switch (kCurrentTrackingSystem) {
74 case kWholeDexTracking:
75 SetDexFileRegistration(true);
76 break;
77 case kCodeItemTracking:
78 SetAllCodeItemRegistration(true);
79 break;
80 case kCodeItemNonInsnsTracking:
81 SetAllCodeItemRegistration(true);
82 SetAllInsnsRegistration(false);
83 break;
84 case kCodeItemNonInsnsNoClinitTracking:
85 SetAllCodeItemRegistration(true);
86 SetAllInsnsRegistration(false);
87 SetCodeItemRegistration("<clinit>", false);
88 break;
89 case kCustomTracking:
90 // TODO: Add/remove additional calls here to (un)poison sections of
91 // dex_file_
92 break;
93 }
94 }
95}
96
97void RegisterDexFile(const DexFile* dex_file) {
98 DexFileTrackingRegistrar dex_tracking_registrar(dex_file);
99 dex_tracking_registrar.SetDexSections();
100 dex_tracking_registrar.SetCurrentRanges();
101}
102
103inline void SetRegistrationRange(const void* begin, size_t size, bool should_poison) {
104 if (should_poison) {
105 MEMORY_TOOL_MAKE_NOACCESS(begin, size);
106 } else {
107 // Note: MEMORY_TOOL_MAKE_UNDEFINED has the same functionality with Address
108 // Sanitizer. The difference has not been tested with Valgrind
109 MEMORY_TOOL_MAKE_DEFINED(begin, size);
110 }
111}
112
113void DexFileTrackingRegistrar::SetCurrentRanges() {
114 // This also empties range_values_ to avoid redundant (un)poisoning upon
115 // subsequent calls.
116 while (!range_values_.empty()) {
117 const std::tuple<const void*, size_t, bool>& current_range = range_values_.front();
118 SetRegistrationRange(std::get<0>(current_range),
119 std::get<1>(current_range),
120 std::get<2>(current_range));
121 range_values_.pop_front();
122 }
123}
124
125void DexFileTrackingRegistrar::SetDexFileRegistration(bool should_poison) {
126 const void* dex_file_begin = reinterpret_cast<const void*>(dex_file_->Begin());
127 size_t dex_file_size = dex_file_->Size();
128 range_values_.push_back(std::make_tuple(dex_file_begin, dex_file_size, should_poison));
129}
130
131void DexFileTrackingRegistrar::SetAllCodeItemRegistration(bool should_poison) {
132 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
133 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
134 const uint8_t* class_data = dex_file_->GetClassData(cd);
135 if (class_data != nullptr) {
136 ClassDataItemIterator cdit(*dex_file_, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -0700137 cdit.SkipAllFields();
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -0700138 while (cdit.HasNextDirectMethod()) {
139 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
140 if (code_item != nullptr) {
141 const void* code_item_begin = reinterpret_cast<const void*>(code_item);
142 size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
143 range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
144 }
145 cdit.Next();
146 }
147 }
148 }
149}
150
151void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) {
152 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
153 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
154 const uint8_t* class_data = dex_file_->GetClassData(cd);
155 if (class_data != nullptr) {
156 ClassDataItemIterator cdit(*dex_file_, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -0700157 cdit.SkipAllFields();
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -0700158 while (cdit.HasNextDirectMethod()) {
159 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
160 if (code_item != nullptr) {
161 const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
162 // Member insns_size_in_code_units_ is in 2-byte units
163 size_t insns_size = code_item->insns_size_in_code_units_ * 2;
164 range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
165 }
166 cdit.Next();
167 }
168 }
169 }
170}
171
172void DexFileTrackingRegistrar::SetCodeItemRegistration(const char* class_name, bool should_poison) {
173 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
174 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
175 const uint8_t* class_data = dex_file_->GetClassData(cd);
176 if (class_data != nullptr) {
177 ClassDataItemIterator cdit(*dex_file_, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -0700178 cdit.SkipAllFields();
Bharadwaj Kalandhabhatta043c9082017-06-06 17:14:12 -0700179 while (cdit.HasNextDirectMethod()) {
180 const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex());
181 const char * methodid_name = dex_file_->GetMethodName(methodid_item);
182 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
183 if (code_item != nullptr && strcmp(methodid_name, class_name) == 0) {
184 const void* code_item_begin = reinterpret_cast<const void*>(code_item);
185 size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
186 range_values_.push_back(
187 std::make_tuple(code_item_begin, code_item_size, should_poison));
188 }
189 cdit.Next();
190 }
191 }
Bharadwaj Kalandhabhatta0bb40312017-06-01 10:47:00 -0700192 }
193}
194
195} // namespace tracking
196} // namespace dex
197} // namespace art