Home | History | Annotate | Download | only in src
      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