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