1 /* 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 19 #include <deque> 20 #include <tuple> 21 22 // 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" 32 #include "dex_file-inl.h" 33 34 namespace art { 35 namespace dex { 36 namespace tracking { 37 38 // If true, poison dex files to track accesses. 39 static constexpr bool kDexFileAccessTracking = 40 #ifdef ART_DEX_FILE_ACCESS_TRACKING 41 true; 42 #else 43 false; 44 #endif 45 46 // The following are configurations of poisoning certain sections of a Dex File. 47 // More will be added 48 enum 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 the size and offset information along with the first instruction. 62 // This is so that accessing multiple instructions while accessing a code item 63 // once will not trigger unnecessary accesses. 64 kCodeItemStartTracking, 65 // Poisons all String Data Items of a Dex Files when set. 66 kStringDataItemTracking, 67 // Poisons the first byte of the utf16_size value and the first byte of the 68 // data section for all String Data Items of a Dex File. 69 kStringDataItemStartTracking, 70 // Poisons based on a custom tracking system which can be specified in 71 // SetDexSections 72 kCustomTracking, 73 }; 74 75 // Intended for local changes only. 76 // Represents the current configuration being run. 77 static constexpr DexTrackingType kCurrentTrackingSystem = kWholeDexTracking; 78 79 // Intended for local changes only. 80 void DexFileTrackingRegistrar::SetDexSections() { 81 if (kDexFileAccessTracking && dex_file_ != nullptr) { 82 // Logs the Dex File's location and starting address if tracking is enabled 83 LOG(ERROR) << "RegisterDexFile: " << dex_file_->GetLocation() + " @ " << std::hex 84 << reinterpret_cast<uintptr_t>(dex_file_->Begin()); 85 switch (kCurrentTrackingSystem) { 86 case kWholeDexTracking: 87 SetDexFileRegistration(true); 88 break; 89 case kCodeItemTracking: 90 SetAllCodeItemRegistration(true); 91 break; 92 case kCodeItemNonInsnsTracking: 93 SetAllCodeItemRegistration(true); 94 SetAllInsnsRegistration(false); 95 break; 96 case kCodeItemNonInsnsNoClinitTracking: 97 SetAllCodeItemRegistration(true); 98 SetAllInsnsRegistration(false); 99 SetCodeItemRegistration("<clinit>", false); 100 break; 101 case kCodeItemStartTracking: 102 SetAllCodeItemStartRegistration(true); 103 break; 104 case kStringDataItemTracking: 105 SetAllStringDataRegistration(true); 106 break; 107 case kStringDataItemStartTracking: 108 SetAllStringDataStartRegistration(true); 109 break; 110 case kCustomTracking: 111 // TODO: Add/remove additional calls here to (un)poison sections of 112 // dex_file_ 113 break; 114 default: 115 break; 116 } 117 } 118 } 119 120 void RegisterDexFile(const DexFile* dex_file) { 121 DexFileTrackingRegistrar dex_tracking_registrar(dex_file); 122 dex_tracking_registrar.SetDexSections(); 123 dex_tracking_registrar.SetCurrentRanges(); 124 } 125 126 inline void SetRegistrationRange(const void* begin, size_t size, bool should_poison) { 127 if (should_poison) { 128 MEMORY_TOOL_MAKE_NOACCESS(begin, size); 129 } else { 130 // Note: MEMORY_TOOL_MAKE_UNDEFINED has the same functionality with Address 131 // Sanitizer. The difference has not been tested with Valgrind 132 MEMORY_TOOL_MAKE_DEFINED(begin, size); 133 } 134 } 135 136 void DexFileTrackingRegistrar::SetCurrentRanges() { 137 // This also empties range_values_ to avoid redundant (un)poisoning upon 138 // subsequent calls. 139 while (!range_values_.empty()) { 140 const std::tuple<const void*, size_t, bool>& current_range = range_values_.front(); 141 SetRegistrationRange(std::get<0>(current_range), 142 std::get<1>(current_range), 143 std::get<2>(current_range)); 144 range_values_.pop_front(); 145 } 146 } 147 148 void DexFileTrackingRegistrar::SetDexFileRegistration(bool should_poison) { 149 const void* dex_file_begin = reinterpret_cast<const void*>(dex_file_->Begin()); 150 size_t dex_file_size = dex_file_->Size(); 151 range_values_.push_back(std::make_tuple(dex_file_begin, dex_file_size, should_poison)); 152 } 153 154 void DexFileTrackingRegistrar::SetAllCodeItemRegistration(bool should_poison) { 155 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) { 156 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr); 157 const uint8_t* class_data = dex_file_->GetClassData(cd); 158 if (class_data != nullptr) { 159 ClassDataItemIterator cdit(*dex_file_, class_data); 160 cdit.SkipAllFields(); 161 while (cdit.HasNextDirectMethod()) { 162 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem(); 163 if (code_item != nullptr) { 164 const void* code_item_begin = reinterpret_cast<const void*>(code_item); 165 size_t code_item_size = DexFile::GetCodeItemSize(*code_item); 166 range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison)); 167 } 168 cdit.Next(); 169 } 170 } 171 } 172 } 173 174 void DexFileTrackingRegistrar::SetAllCodeItemStartRegistration(bool should_poison) { 175 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) { 176 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr); 177 const uint8_t* class_data = dex_file_->GetClassData(cd); 178 if (class_data != nullptr) { 179 ClassDataItemIterator cdit(*dex_file_, class_data); 180 cdit.SkipAllFields(); 181 while (cdit.HasNextDirectMethod()) { 182 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem(); 183 if (code_item != nullptr) { 184 const void* code_item_begin = reinterpret_cast<const void*>(code_item); 185 size_t code_item_start = reinterpret_cast<size_t>(code_item); 186 size_t code_item_start_end = reinterpret_cast<size_t>(&code_item->insns_[1]); 187 size_t code_item_start_size = code_item_start_end - code_item_start; 188 range_values_.push_back(std::make_tuple(code_item_begin, code_item_start_size, should_poison)); 189 } 190 cdit.Next(); 191 } 192 } 193 } 194 } 195 196 void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) { 197 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) { 198 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr); 199 const uint8_t* class_data = dex_file_->GetClassData(cd); 200 if (class_data != nullptr) { 201 ClassDataItemIterator cdit(*dex_file_, class_data); 202 cdit.SkipAllFields(); 203 while (cdit.HasNextDirectMethod()) { 204 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem(); 205 if (code_item != nullptr) { 206 const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_); 207 // Member insns_size_in_code_units_ is in 2-byte units 208 size_t insns_size = code_item->insns_size_in_code_units_ * 2; 209 range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison)); 210 } 211 cdit.Next(); 212 } 213 } 214 } 215 } 216 217 void DexFileTrackingRegistrar::SetCodeItemRegistration(const char* class_name, bool should_poison) { 218 for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) { 219 const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr); 220 const uint8_t* class_data = dex_file_->GetClassData(cd); 221 if (class_data != nullptr) { 222 ClassDataItemIterator cdit(*dex_file_, class_data); 223 cdit.SkipAllFields(); 224 while (cdit.HasNextDirectMethod()) { 225 const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex()); 226 const char * methodid_name = dex_file_->GetMethodName(methodid_item); 227 const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem(); 228 if (code_item != nullptr && strcmp(methodid_name, class_name) == 0) { 229 const void* code_item_begin = reinterpret_cast<const void*>(code_item); 230 size_t code_item_size = DexFile::GetCodeItemSize(*code_item); 231 range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison)); 232 } 233 cdit.Next(); 234 } 235 } 236 } 237 } 238 239 void DexFileTrackingRegistrar::SetAllStringDataStartRegistration(bool should_poison) { 240 for (size_t stringid_ctr = 0; stringid_ctr < dex_file_->NumStringIds(); ++stringid_ctr) { 241 const DexFile::StringId & string_id = dex_file_->GetStringId(StringIndex(stringid_ctr)); 242 const void* string_data_begin = reinterpret_cast<const void*>(dex_file_->Begin() + string_id.string_data_off_); 243 // Data Section of String Data Item 244 const void* string_data_data_begin = reinterpret_cast<const void*>(dex_file_->GetStringData(string_id)); 245 range_values_.push_back(std::make_tuple(string_data_begin, 1, should_poison)); 246 range_values_.push_back(std::make_tuple(string_data_data_begin, 1, should_poison)); 247 } 248 } 249 250 void DexFileTrackingRegistrar::SetAllStringDataRegistration(bool should_poison) { 251 size_t map_offset = dex_file_->GetHeader().map_off_; 252 auto map_list = reinterpret_cast<const DexFile::MapList*>(dex_file_->Begin() + map_offset); 253 for (size_t map_ctr = 0; map_ctr < map_list->size_; ++map_ctr) { 254 const DexFile::MapItem& map_item = map_list->list_[map_ctr]; 255 if (map_item.type_ == DexFile::kDexTypeStringDataItem) { 256 const DexFile::MapItem& next_map_item = map_list->list_[map_ctr + 1]; 257 const void* string_data_begin = reinterpret_cast<const void*>(dex_file_->Begin() + map_item.offset_); 258 size_t string_data_size = next_map_item.offset_ - map_item.offset_; 259 range_values_.push_back(std::make_tuple(string_data_begin, string_data_size, should_poison)); 260 } 261 } 262 } 263 264 } // namespace tracking 265 } // namespace dex 266 } // namespace art 267