crazy_linker_shared_library.cpp revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2014 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
61namespace crazy {
62
63namespace {
64
65typedef SharedLibrary::linker_function_t linker_function_t;
66typedef int (*JNI_OnLoadFunctionPtr)(void* vm, void* reserved);
67typedef 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...).
74void 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.
85class 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
153SharedLibrary::SharedLibrary() { ::memset(this, 0, sizeof(*this)); }
154
155SharedLibrary::~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
161bool 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
287bool 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
306const ELF::Sym* SharedLibrary::LookupSymbolEntry(const char* symbol_name) {
307  return symbols_.LookupByName(symbol_name);
308}
309
310void* SharedLibrary::FindAddressForSymbol(const char* symbol_name) {
311  return symbols_.LookupAddressByName(symbol_name, view_.load_bias());
312}
313
314bool 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
347bool 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
387void 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
393void 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
400bool 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
426void 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
438bool 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