1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "crazy_linker_shared_library.h" 6 7 #include <dlfcn.h> 8 #include <stdlib.h> 9 #include <sys/mman.h> 10 #include <elf.h> 11 12 #include "crazy_linker_ashmem.h" 13 #include "crazy_linker_debug.h" 14 #include "crazy_linker_elf_loader.h" 15 #include "crazy_linker_elf_relocations.h" 16 #include "crazy_linker_library_list.h" 17 #include "crazy_linker_library_view.h" 18 #include "crazy_linker_globals.h" 19 #include "crazy_linker_memory_mapping.h" 20 #include "crazy_linker_thread.h" 21 #include "crazy_linker_util.h" 22 #include "crazy_linker_wrappers.h" 23 #include "linker_phdr.h" 24 25 #ifndef DF_SYMBOLIC 26 #define DF_SYMBOLIC 2 27 #endif 28 29 #ifndef DF_TEXTREL 30 #define DF_TEXTREL 4 31 #endif 32 33 #ifndef DT_INIT_ARRAY 34 #define DT_INIT_ARRAY 25 35 #endif 36 37 #ifndef DT_INIT_ARRAYSZ 38 #define DT_INIT_ARRAYSZ 27 39 #endif 40 41 #ifndef DT_FINI_ARRAY 42 #define DT_FINI_ARRAY 26 43 #endif 44 45 #ifndef DT_FINI_ARRAYSZ 46 #define DT_FINI_ARRAYSZ 28 47 #endif 48 49 #ifndef DT_FLAGS 50 #define DT_FLAGS 30 51 #endif 52 53 #ifndef DT_PREINIT_ARRAY 54 #define DT_PREINIT_ARRAY 32 55 #endif 56 57 #ifndef DT_PREINIT_ARRAYSZ 58 #define DT_PREINIT_ARRAYSZ 33 59 #endif 60 61 namespace crazy { 62 63 namespace { 64 65 typedef SharedLibrary::linker_function_t linker_function_t; 66 typedef int (*JNI_OnLoadFunctionPtr)(void* vm, void* reserved); 67 typedef void (*JNI_OnUnloadFunctionPtr)(void* vm, void* reserved); 68 69 // Call a constructor or destructor function pointer. Ignore 70 // NULL and -1 values intentionally. They correspond to markers 71 // in the tables, or deleted values. 72 // |func_type| corresponds to the type of the function, and is only 73 // used for debugging (examples are "DT_INIT", "DT_INIT_ARRAY", etc...). 74 void CallFunction(linker_function_t func, const char* func_type) { 75 uintptr_t func_address = reinterpret_cast<uintptr_t>(func); 76 77 LOG("%s: %p %s\n", __FUNCTION__, func, func_type); 78 if (func_address != 0 && func_address != uintptr_t(-1)) 79 func(); 80 } 81 82 // An instance of ElfRelocator::SymbolResolver that can be used 83 // to resolve symbols in a shared library being loaded by 84 // LibraryList::LoadLibrary. 85 class SharedLibraryResolver : public ElfRelocations::SymbolResolver { 86 public: 87 SharedLibraryResolver(SharedLibrary* lib, 88 LibraryList* lib_list, 89 Vector<LibraryView*>* dependencies) 90 : lib_(lib), dependencies_(dependencies) {} 91 92 virtual void* Lookup(const char* symbol_name) { 93 // TODO(digit): Add the ability to lookup inside the main executable. 94 95 // First, look inside the current library. 96 const ELF::Sym* entry = lib_->LookupSymbolEntry(symbol_name); 97 if (entry) 98 return reinterpret_cast<void*>(lib_->load_bias() + entry->st_value); 99 100 // Special case: redirect the dynamic linker symbols to our wrappers. 101 // This ensures that loaded libraries can call dlopen() / dlsym() 102 // and transparently use the crazy linker to perform their duty. 103 void* address = WrapLinkerSymbol(symbol_name); 104 if (address) 105 return address; 106 107 // Then look inside the dependencies. 108 for (size_t n = 0; n < dependencies_->GetCount(); ++n) { 109 LibraryView* wrap = (*dependencies_)[n]; 110 // LOG("%s: Looking into dependency %p (%s)\n", __FUNCTION__, wrap, 111 // wrap->GetName()); 112 if (wrap->IsSystem()) { 113 address = ::dlsym(wrap->GetSystem(), symbol_name); 114 #ifdef __arm__ 115 // Android libm.so defines isnanf as weak. This means that its 116 // address cannot be found by dlsym(), which always returns NULL 117 // for weak symbols. However, libm.so contains the real isnanf 118 // as __isnanf. If we encounter isnanf and fail to resolve it in 119 // libm.so, retry with __isnanf. 120 // 121 // This occurs only in clang, which lacks __builtin_isnanf. The 122 // gcc compiler implements isnanf as a builtin, so the symbol 123 // isnanf never need be resolved in gcc builds. 124 // 125 // http://code.google.com/p/chromium/issues/detail?id=376828 126 if (!address && 127 !strcmp(symbol_name, "isnanf") && 128 !strcmp(wrap->GetName(), "libm.so")) 129 address = ::dlsym(wrap->GetSystem(), "__isnanf"); 130 #endif 131 if (address) 132 return address; 133 } 134 if (wrap->IsCrazy()) { 135 SharedLibrary* dep = wrap->GetCrazy(); 136 entry = dep->LookupSymbolEntry(symbol_name); 137 if (entry) 138 return reinterpret_cast<void*>(dep->load_bias() + entry->st_value); 139 } 140 } 141 142 // Nothing found here. 143 return NULL; 144 } 145 146 private: 147 SharedLibrary* lib_; 148 Vector<LibraryView*>* dependencies_; 149 }; 150 151 } // namespace 152 153 SharedLibrary::SharedLibrary() { ::memset(this, 0, sizeof(*this)); } 154 155 SharedLibrary::~SharedLibrary() { 156 // Ensure the library is unmapped on destruction. 157 if (view_.load_address()) 158 munmap(reinterpret_cast<void*>(view_.load_address()), view_.load_size()); 159 } 160 161 bool SharedLibrary::Load(const char* full_path, 162 size_t load_address, 163 size_t file_offset, 164 Error* error) { 165 // First, record the path. 166 LOG("%s: full path '%s'\n", __FUNCTION__, full_path); 167 168 size_t full_path_len = strlen(full_path); 169 if (full_path_len >= sizeof(full_path_)) { 170 error->Format("Path too long: %s", full_path); 171 return false; 172 } 173 174 strlcpy(full_path_, full_path, sizeof(full_path_)); 175 base_name_ = GetBaseNamePtr(full_path_); 176 177 // Load the ELF binary in memory. 178 LOG("%s: Loading ELF segments for %s\n", __FUNCTION__, base_name_); 179 180 { 181 ElfLoader loader; 182 if (!loader.LoadAt(full_path_, file_offset, load_address, error)) { 183 return false; 184 } 185 186 if (!view_.InitUnmapped(loader.load_start(), 187 loader.loaded_phdr(), 188 loader.phdr_count(), 189 error)) { 190 return false; 191 } 192 193 if (!symbols_.Init(&view_)) { 194 *error = "Missing or malformed symbol table"; 195 return false; 196 } 197 } 198 199 if (phdr_table_get_relro_info(view_.phdr(), 200 view_.phdr_count(), 201 view_.load_bias(), 202 &relro_start_, 203 &relro_size_) < 0) { 204 relro_start_ = 0; 205 relro_size_ = 0; 206 } 207 208 #ifdef __arm__ 209 LOG("%s: Extracting ARM.exidx table for %s\n", __FUNCTION__, base_name_); 210 (void)phdr_table_get_arm_exidx( 211 phdr(), phdr_count(), load_bias(), &arm_exidx_, &arm_exidx_count_); 212 #endif 213 214 LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_); 215 ElfView::DynamicIterator dyn(&view_); 216 for (; dyn.HasNext(); dyn.GetNext()) { 217 ELF::Addr dyn_value = dyn.GetValue(); 218 uintptr_t dyn_addr = dyn.GetAddress(load_bias()); 219 switch (dyn.GetTag()) { 220 case DT_DEBUG: 221 if (view_.dynamic_flags() & PF_W) { 222 *dyn.GetValuePointer() = 223 reinterpret_cast<uintptr_t>(Globals::GetRDebug()->GetAddress()); 224 } 225 break; 226 case DT_INIT: 227 LOG(" DT_INIT addr=%p\n", dyn_addr); 228 init_func_ = reinterpret_cast<linker_function_t>(dyn_addr); 229 break; 230 case DT_FINI: 231 LOG(" DT_FINI addr=%p\n", dyn_addr); 232 fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr); 233 break; 234 case DT_INIT_ARRAY: 235 LOG(" DT_INIT_ARRAY addr=%p\n", dyn_addr); 236 init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); 237 break; 238 case DT_INIT_ARRAYSZ: 239 init_array_count_ = dyn_value / sizeof(ELF::Addr); 240 LOG(" DT_INIT_ARRAYSZ value=%p count=%p\n", 241 dyn_value, 242 init_array_count_); 243 break; 244 case DT_FINI_ARRAY: 245 LOG(" DT_FINI_ARRAY addr=%p\n", dyn_addr); 246 fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); 247 break; 248 case DT_FINI_ARRAYSZ: 249 fini_array_count_ = dyn_value / sizeof(ELF::Addr); 250 LOG(" DT_FINI_ARRAYSZ value=%p count=%p\n", 251 dyn_value, 252 fini_array_count_); 253 break; 254 case DT_PREINIT_ARRAY: 255 LOG(" DT_PREINIT_ARRAY addr=%p\n", dyn_addr); 256 preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); 257 break; 258 case DT_PREINIT_ARRAYSZ: 259 preinit_array_count_ = dyn_value / sizeof(ELF::Addr); 260 LOG(" DT_PREINIT_ARRAYSZ value=%p count=%p\n", 261 dyn_value, 262 preinit_array_count_); 263 break; 264 case DT_SYMBOLIC: 265 LOG(" DT_SYMBOLIC\n"); 266 has_DT_SYMBOLIC_ = true; 267 break; 268 case DT_FLAGS: 269 if (dyn_value & DF_SYMBOLIC) 270 has_DT_SYMBOLIC_ = true; 271 break; 272 #if defined(__mips__) 273 case DT_MIPS_RLD_MAP: 274 *dyn.GetValuePointer() = 275 reinterpret_cast<ELF::Addr>(Globals::GetRDebug()->GetAddress()); 276 break; 277 #endif 278 default: 279 ; 280 } 281 } 282 283 LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_); 284 return true; 285 } 286 287 bool SharedLibrary::Relocate(LibraryList* lib_list, 288 Vector<LibraryView*>* dependencies, 289 Error* error) { 290 // Apply relocations. 291 LOG("%s: Applying relocations to %s\n", __FUNCTION__, base_name_); 292 293 ElfRelocations relocations; 294 295 if (!relocations.Init(&view_, error)) 296 return false; 297 298 SharedLibraryResolver resolver(this, lib_list, dependencies); 299 if (!relocations.ApplyAll(&symbols_, &resolver, error)) 300 return false; 301 302 LOG("%s: Relocations applied for %s\n", __FUNCTION__, base_name_); 303 return true; 304 } 305 306 const ELF::Sym* SharedLibrary::LookupSymbolEntry(const char* symbol_name) { 307 return symbols_.LookupByName(symbol_name); 308 } 309 310 void* SharedLibrary::FindAddressForSymbol(const char* symbol_name) { 311 return symbols_.LookupAddressByName(symbol_name, view_.load_bias()); 312 } 313 314 bool SharedLibrary::CreateSharedRelro(size_t load_address, 315 size_t* relro_start, 316 size_t* relro_size, 317 int* relro_fd, 318 Error* error) { 319 SharedRelro relro; 320 321 if (!relro.Allocate(relro_size_, base_name_, error)) 322 return false; 323 324 if (load_address != 0 && load_address != this->load_address()) { 325 // Need to relocate the content of the ashmem region first to accomodate 326 // for the new load address. 327 if (!relro.CopyFromRelocated( 328 &view_, load_address, relro_start_, relro_size_, error)) 329 return false; 330 } else { 331 // Simply copy, no relocations. 332 if (!relro.CopyFrom(relro_start_, relro_size_, error)) 333 return false; 334 } 335 336 // Enforce read-only mode for the region's content. 337 if (!relro.ForceReadOnly(error)) 338 return false; 339 340 // All good. 341 *relro_start = relro.start(); 342 *relro_size = relro.size(); 343 *relro_fd = relro.DetachFd(); 344 return true; 345 } 346 347 bool SharedLibrary::UseSharedRelro(size_t relro_start, 348 size_t relro_size, 349 int relro_fd, 350 Error* error) { 351 LOG("%s: relro_start=%p relro_size=%p relro_fd=%d\n", 352 __FUNCTION__, 353 (void*)relro_start, 354 (void*)relro_size, 355 relro_fd); 356 357 if (relro_fd < 0 || relro_size == 0) { 358 // Nothing to do here. 359 return true; 360 } 361 362 // Sanity check: A shared RELRO is not already used. 363 if (relro_used_) { 364 *error = "Library already using shared RELRO section"; 365 return false; 366 } 367 368 // Sanity check: RELRO addresses must match. 369 if (relro_start_ != relro_start || relro_size_ != relro_size) { 370 error->Format("RELRO mismatch addr=%p size=%p (wanted addr=%p size=%p)", 371 relro_start_, 372 relro_size_, 373 relro_start, 374 relro_size); 375 return false; 376 } 377 378 // Everything's good, swap pages in this process's address space. 379 SharedRelro relro; 380 if (!relro.InitFrom(relro_start, relro_size, relro_fd, error)) 381 return false; 382 383 relro_used_ = true; 384 return true; 385 } 386 387 void SharedLibrary::CallConstructors() { 388 CallFunction(init_func_, "DT_INIT"); 389 for (size_t n = 0; n < init_array_count_; ++n) 390 CallFunction(init_array_[n], "DT_INIT_ARRAY"); 391 } 392 393 void SharedLibrary::CallDestructors() { 394 for (size_t n = fini_array_count_; n > 0; --n) { 395 CallFunction(fini_array_[n - 1], "DT_FINI_ARRAY"); 396 } 397 CallFunction(fini_func_, "DT_FINI"); 398 } 399 400 bool SharedLibrary::SetJavaVM(void* java_vm, 401 int minimum_jni_version, 402 Error* error) { 403 if (java_vm == NULL) 404 return true; 405 406 // Lookup for JNI_OnLoad, exit if it doesn't exist. 407 JNI_OnLoadFunctionPtr jni_onload = reinterpret_cast<JNI_OnLoadFunctionPtr>( 408 FindAddressForSymbol("JNI_OnLoad")); 409 if (!jni_onload) 410 return true; 411 412 int jni_version = (*jni_onload)(java_vm, NULL); 413 if (jni_version < minimum_jni_version) { 414 error->Format("JNI_OnLoad() in %s returned %d, expected at least %d", 415 full_path_, 416 jni_version, 417 minimum_jni_version); 418 return false; 419 } 420 421 // Save the JavaVM handle for unload time. 422 java_vm_ = java_vm; 423 return true; 424 } 425 426 void SharedLibrary::CallJniOnUnload() { 427 if (!java_vm_) 428 return; 429 430 JNI_OnUnloadFunctionPtr jni_on_unload = 431 reinterpret_cast<JNI_OnUnloadFunctionPtr>( 432 this->FindAddressForSymbol("JNI_OnUnload")); 433 434 if (jni_on_unload) 435 (*jni_on_unload)(java_vm_, NULL); 436 } 437 438 bool SharedLibrary::DependencyIterator::GetNext() { 439 dep_name_ = NULL; 440 for (; iter_.HasNext(); iter_.GetNext()) { 441 if (iter_.GetTag() == DT_NEEDED) { 442 dep_name_ = symbols_->GetStringById(iter_.GetValue()); 443 iter_.GetNext(); 444 return true; 445 } 446 } 447 return false; 448 } 449 450 } // namespace crazy 451