crazy_linker_shared_library.cpp revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
61#ifndef DT_LOOS
62#define DT_LOOS 0x6000000d
63#endif
64
65// Extension dynamic tags for packed relocations.
66#ifdef __arm__
67
68#define DT_ANDROID_REL_OFFSET (DT_LOOS)
69#define DT_ANDROID_REL_SIZE (DT_LOOS + 1)
70
71#endif  // __arm__
72
73namespace crazy {
74
75namespace {
76
77typedef SharedLibrary::linker_function_t linker_function_t;
78typedef int (*JNI_OnLoadFunctionPtr)(void* vm, void* reserved);
79typedef void (*JNI_OnUnloadFunctionPtr)(void* vm, void* reserved);
80
81// Call a constructor or destructor function pointer. Ignore
82// NULL and -1 values intentionally. They correspond to markers
83// in the tables, or deleted values.
84// |func_type| corresponds to the type of the function, and is only
85// used for debugging (examples are "DT_INIT", "DT_INIT_ARRAY", etc...).
86void CallFunction(linker_function_t func, const char* func_type) {
87  uintptr_t func_address = reinterpret_cast<uintptr_t>(func);
88
89  LOG("%s: %p %s\n", __FUNCTION__, func, func_type);
90  if (func_address != 0 && func_address != uintptr_t(-1))
91    func();
92}
93
94// An instance of ElfRelocator::SymbolResolver that can be used
95// to resolve symbols in a shared library being loaded by
96// LibraryList::LoadLibrary.
97class SharedLibraryResolver : public ElfRelocations::SymbolResolver {
98 public:
99  SharedLibraryResolver(SharedLibrary* lib,
100                        LibraryList* lib_list,
101                        Vector<LibraryView*>* dependencies)
102      : lib_(lib), dependencies_(dependencies) {}
103
104  virtual void* Lookup(const char* symbol_name) {
105    // TODO(digit): Add the ability to lookup inside the main executable.
106
107    // First, look inside the current library.
108    const ELF::Sym* entry = lib_->LookupSymbolEntry(symbol_name);
109    if (entry)
110      return reinterpret_cast<void*>(lib_->load_bias() + entry->st_value);
111
112    // Special case: redirect the dynamic linker symbols to our wrappers.
113    // This ensures that loaded libraries can call dlopen() / dlsym()
114    // and transparently use the crazy linker to perform their duty.
115    void* address = WrapLinkerSymbol(symbol_name);
116    if (address)
117      return address;
118
119    // Then look inside the dependencies.
120    for (size_t n = 0; n < dependencies_->GetCount(); ++n) {
121      LibraryView* wrap = (*dependencies_)[n];
122      // LOG("%s: Looking into dependency %p (%s)\n", __FUNCTION__, wrap,
123      // wrap->GetName());
124      if (wrap->IsSystem()) {
125        address = ::dlsym(wrap->GetSystem(), symbol_name);
126#ifdef __arm__
127        // Android libm.so defines isnanf as weak. This means that its
128        // address cannot be found by dlsym(), which always returns NULL
129        // for weak symbols. However, libm.so contains the real isnanf
130        // as __isnanf. If we encounter isnanf and fail to resolve it in
131        // libm.so, retry with __isnanf.
132        //
133        // This occurs only in clang, which lacks __builtin_isnanf. The
134        // gcc compiler implements isnanf as a builtin, so the symbol
135        // isnanf never need be resolved in gcc builds.
136        //
137        // http://code.google.com/p/chromium/issues/detail?id=376828
138        if (!address &&
139            !strcmp(symbol_name, "isnanf") &&
140            !strcmp(wrap->GetName(), "libm.so"))
141          address = ::dlsym(wrap->GetSystem(), "__isnanf");
142#endif
143        if (address)
144          return address;
145      }
146      if (wrap->IsCrazy()) {
147        SharedLibrary* dep = wrap->GetCrazy();
148        entry = dep->LookupSymbolEntry(symbol_name);
149        if (entry)
150          return reinterpret_cast<void*>(dep->load_bias() + entry->st_value);
151      }
152    }
153
154    // Nothing found here.
155    return NULL;
156  }
157
158 private:
159  SharedLibrary* lib_;
160  Vector<LibraryView*>* dependencies_;
161};
162
163#ifdef __arm__
164
165// Helper class to provide a simple scoped buffer.  ScopedPtr is not
166// usable here because it calls delete, not delete [].
167class ScopedBuffer {
168 public:
169  explicit ScopedBuffer(size_t bytes) : buffer_(new uint8_t[bytes]) { }
170  ~ScopedBuffer() { delete [] buffer_; }
171
172  uint8_t* Get() { return buffer_; }
173
174  uint8_t* Release() {
175    uint8_t* ptr = buffer_;
176    buffer_ = NULL;
177    return ptr;
178  }
179
180 private:
181  uint8_t* buffer_;
182};
183
184// Read an .android.rel.dyn ARM packed relocations section.
185// Returns an allocated buffer holding the data, or NULL on error.
186uint8_t* ReadArmPackedRelocs(const char* full_path,
187                             off_t offset,
188                             size_t bytes,
189                             Error* error) {
190  FileDescriptor fd;
191  if (!fd.OpenReadOnly(full_path)) {
192    error->Format("Error opening file '%s'", full_path);
193    return NULL;
194  }
195  if (fd.SeekTo(offset) == -1) {
196    error->Format("Error seeking to %d in file '%s'", offset, full_path);
197    return NULL;
198  }
199
200  ScopedBuffer buffer(bytes);
201  const ssize_t bytes_read = fd.Read(buffer.Get(), bytes);
202  if (static_cast<size_t>(bytes_read) != bytes) {
203    error->Format("Error reading %d bytes from file '%s'", bytes, full_path);
204    return NULL;
205  }
206  fd.Close();
207
208  uint8_t* packed_data = buffer.Release();
209  return packed_data;
210}
211
212#endif  // __arm__
213
214}  // namespace
215
216SharedLibrary::SharedLibrary() { ::memset(this, 0, sizeof(*this)); }
217
218SharedLibrary::~SharedLibrary() {
219  // Ensure the library is unmapped on destruction.
220  if (view_.load_address())
221    munmap(reinterpret_cast<void*>(view_.load_address()), view_.load_size());
222
223#ifdef __arm__
224  delete [] arm_packed_relocs_;
225#endif
226}
227
228bool SharedLibrary::Load(const char* full_path,
229                         size_t load_address,
230                         size_t file_offset,
231                         Error* error) {
232  // First, record the path.
233  LOG("%s: full path '%s'\n", __FUNCTION__, full_path);
234
235  size_t full_path_len = strlen(full_path);
236  if (full_path_len >= sizeof(full_path_)) {
237    error->Format("Path too long: %s", full_path);
238    return false;
239  }
240
241  strlcpy(full_path_, full_path, sizeof(full_path_));
242  base_name_ = GetBaseNamePtr(full_path_);
243
244  // Load the ELF binary in memory.
245  LOG("%s: Loading ELF segments for %s\n", __FUNCTION__, base_name_);
246
247  {
248    ElfLoader loader;
249    if (!loader.LoadAt(full_path_, file_offset, load_address, error)) {
250      return false;
251    }
252
253    if (!view_.InitUnmapped(loader.load_start(),
254                            loader.loaded_phdr(),
255                            loader.phdr_count(),
256                            error)) {
257      return false;
258    }
259
260    if (!symbols_.Init(&view_)) {
261      *error = "Missing or malformed symbol table";
262      return false;
263    }
264  }
265
266  if (phdr_table_get_relro_info(view_.phdr(),
267                                view_.phdr_count(),
268                                view_.load_bias(),
269                                &relro_start_,
270                                &relro_size_) < 0) {
271    relro_start_ = 0;
272    relro_size_ = 0;
273  }
274
275#ifdef __arm__
276  LOG("%s: Extracting ARM.exidx table for %s\n", __FUNCTION__, base_name_);
277  (void)phdr_table_get_arm_exidx(
278      phdr(), phdr_count(), load_bias(), &arm_exidx_, &arm_exidx_count_);
279
280  off_t arm_packed_relocs_offset = 0;
281  size_t arm_packed_relocs_size = 0;
282#endif
283
284  LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_);
285  ElfView::DynamicIterator dyn(&view_);
286  for (; dyn.HasNext(); dyn.GetNext()) {
287    ELF::Addr dyn_value = dyn.GetValue();
288    uintptr_t dyn_addr = dyn.GetAddress(load_bias());
289    switch (dyn.GetTag()) {
290      case DT_DEBUG:
291        if (view_.dynamic_flags() & PF_W) {
292          *dyn.GetValuePointer() =
293              reinterpret_cast<uintptr_t>(Globals::GetRDebug()->GetAddress());
294        }
295        break;
296      case DT_INIT:
297        LOG("  DT_INIT addr=%p\n", dyn_addr);
298        init_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
299        break;
300      case DT_FINI:
301        LOG("  DT_FINI addr=%p\n", dyn_addr);
302        fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
303        break;
304      case DT_INIT_ARRAY:
305        LOG("  DT_INIT_ARRAY addr=%p\n", dyn_addr);
306        init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
307        break;
308      case DT_INIT_ARRAYSZ:
309        init_array_count_ = dyn_value / sizeof(ELF::Addr);
310        LOG("  DT_INIT_ARRAYSZ value=%p count=%p\n",
311            dyn_value,
312            init_array_count_);
313        break;
314      case DT_FINI_ARRAY:
315        LOG("  DT_FINI_ARRAY addr=%p\n", dyn_addr);
316        fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
317        break;
318      case DT_FINI_ARRAYSZ:
319        fini_array_count_ = dyn_value / sizeof(ELF::Addr);
320        LOG("  DT_FINI_ARRAYSZ value=%p count=%p\n",
321            dyn_value,
322            fini_array_count_);
323        break;
324      case DT_PREINIT_ARRAY:
325        LOG("  DT_PREINIT_ARRAY addr=%p\n", dyn_addr);
326        preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
327        break;
328      case DT_PREINIT_ARRAYSZ:
329        preinit_array_count_ = dyn_value / sizeof(ELF::Addr);
330        LOG("  DT_PREINIT_ARRAYSZ value=%p count=%p\n",
331            dyn_value,
332            preinit_array_count_);
333        break;
334      case DT_SYMBOLIC:
335        LOG("  DT_SYMBOLIC\n");
336        has_DT_SYMBOLIC_ = true;
337        break;
338      case DT_FLAGS:
339        if (dyn_value & DF_SYMBOLIC)
340          has_DT_SYMBOLIC_ = true;
341        break;
342#if defined(__arm__)
343      case DT_ANDROID_REL_OFFSET:
344        arm_packed_relocs_offset = dyn.GetOffset();
345        LOG("  DT_ANDROID_REL_OFFSET addr=%p\n", arm_packed_relocs_offset);
346        break;
347      case DT_ANDROID_REL_SIZE:
348        arm_packed_relocs_size = dyn.GetValue();
349        LOG("  DT_ANDROID_REL_SIZE=%d\n", arm_packed_relocs_size);
350        break;
351#endif
352#if defined(__mips__)
353      case DT_MIPS_RLD_MAP:
354        *dyn.GetValuePointer() =
355            reinterpret_cast<ELF::Addr>(Globals::GetRDebug()->GetAddress());
356        break;
357#endif
358      default:
359        ;
360    }
361  }
362
363#ifdef __arm__
364  // If ARM packed relocations are present in the target library, read the
365  // section data and save it in arm_packed_relocs_.
366  if (arm_packed_relocs_offset && arm_packed_relocs_size) {
367    LOG("%s: ARM packed relocations found at offset %d, %d bytes\n",
368        __FUNCTION__,
369        arm_packed_relocs_offset,
370        arm_packed_relocs_size);
371
372    arm_packed_relocs_ =
373        ReadArmPackedRelocs(full_path,
374                            arm_packed_relocs_offset + file_offset,
375                            arm_packed_relocs_size,
376                            error);
377    if (!arm_packed_relocs_)
378      return false;
379
380    LOG("%s: ARM packed relocations stored at %p\n",
381        __FUNCTION__,
382        arm_packed_relocs_);
383  }
384#endif
385
386  LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_);
387  return true;
388}
389
390bool SharedLibrary::Relocate(LibraryList* lib_list,
391                             Vector<LibraryView*>* dependencies,
392                             Error* error) {
393  // Apply relocations.
394  LOG("%s: Applying relocations to %s\n", __FUNCTION__, base_name_);
395
396  ElfRelocations relocations;
397
398  if (!relocations.Init(&view_, error))
399    return false;
400
401#ifdef __arm__
402  relocations.RegisterArmPackedRelocs(arm_packed_relocs_);
403#endif
404
405  SharedLibraryResolver resolver(this, lib_list, dependencies);
406  if (!relocations.ApplyAll(&symbols_, &resolver, error))
407    return false;
408
409  LOG("%s: Relocations applied for %s\n", __FUNCTION__, base_name_);
410  return true;
411}
412
413const ELF::Sym* SharedLibrary::LookupSymbolEntry(const char* symbol_name) {
414  return symbols_.LookupByName(symbol_name);
415}
416
417void* SharedLibrary::FindAddressForSymbol(const char* symbol_name) {
418  return symbols_.LookupAddressByName(symbol_name, view_.load_bias());
419}
420
421bool SharedLibrary::CreateSharedRelro(size_t load_address,
422                                      size_t* relro_start,
423                                      size_t* relro_size,
424                                      int* relro_fd,
425                                      Error* error) {
426  SharedRelro relro;
427
428  if (!relro.Allocate(relro_size_, base_name_, error))
429    return false;
430
431  if (load_address != 0 && load_address != this->load_address()) {
432    // Need to relocate the content of the ashmem region first to accomodate
433    // for the new load address.
434    if (!relro.CopyFromRelocated(
435             &view_, load_address, relro_start_, relro_size_, error))
436      return false;
437  } else {
438    // Simply copy, no relocations.
439    if (!relro.CopyFrom(relro_start_, relro_size_, error))
440      return false;
441  }
442
443  // Enforce read-only mode for the region's content.
444  if (!relro.ForceReadOnly(error))
445    return false;
446
447  // All good.
448  *relro_start = relro.start();
449  *relro_size = relro.size();
450  *relro_fd = relro.DetachFd();
451  return true;
452}
453
454bool SharedLibrary::UseSharedRelro(size_t relro_start,
455                                   size_t relro_size,
456                                   int relro_fd,
457                                   Error* error) {
458  LOG("%s: relro_start=%p relro_size=%p relro_fd=%d\n",
459      __FUNCTION__,
460      (void*)relro_start,
461      (void*)relro_size,
462      relro_fd);
463
464  if (relro_fd < 0 || relro_size == 0) {
465    // Nothing to do here.
466    return true;
467  }
468
469  // Sanity check: A shared RELRO is not already used.
470  if (relro_used_) {
471    *error = "Library already using shared RELRO section";
472    return false;
473  }
474
475  // Sanity check: RELRO addresses must match.
476  if (relro_start_ != relro_start || relro_size_ != relro_size) {
477    error->Format("RELRO mismatch addr=%p size=%p (wanted addr=%p size=%p)",
478                  relro_start_,
479                  relro_size_,
480                  relro_start,
481                  relro_size);
482    return false;
483  }
484
485  // Everything's good, swap pages in this process's address space.
486  SharedRelro relro;
487  if (!relro.InitFrom(relro_start, relro_size, relro_fd, error))
488    return false;
489
490  relro_used_ = true;
491  return true;
492}
493
494void SharedLibrary::CallConstructors() {
495  CallFunction(init_func_, "DT_INIT");
496  for (size_t n = 0; n < init_array_count_; ++n)
497    CallFunction(init_array_[n], "DT_INIT_ARRAY");
498}
499
500void SharedLibrary::CallDestructors() {
501  for (size_t n = fini_array_count_; n > 0; --n) {
502    CallFunction(fini_array_[n - 1], "DT_FINI_ARRAY");
503  }
504  CallFunction(fini_func_, "DT_FINI");
505}
506
507bool SharedLibrary::SetJavaVM(void* java_vm,
508                              int minimum_jni_version,
509                              Error* error) {
510  if (java_vm == NULL)
511    return true;
512
513  // Lookup for JNI_OnLoad, exit if it doesn't exist.
514  JNI_OnLoadFunctionPtr jni_onload = reinterpret_cast<JNI_OnLoadFunctionPtr>(
515      FindAddressForSymbol("JNI_OnLoad"));
516  if (!jni_onload)
517    return true;
518
519  int jni_version = (*jni_onload)(java_vm, NULL);
520  if (jni_version < minimum_jni_version) {
521    error->Format("JNI_OnLoad() in %s returned %d, expected at least %d",
522                  full_path_,
523                  jni_version,
524                  minimum_jni_version);
525    return false;
526  }
527
528  // Save the JavaVM handle for unload time.
529  java_vm_ = java_vm;
530  return true;
531}
532
533void SharedLibrary::CallJniOnUnload() {
534  if (!java_vm_)
535    return;
536
537  JNI_OnUnloadFunctionPtr jni_on_unload =
538      reinterpret_cast<JNI_OnUnloadFunctionPtr>(
539          this->FindAddressForSymbol("JNI_OnUnload"));
540
541  if (jni_on_unload)
542    (*jni_on_unload)(java_vm_, NULL);
543}
544
545bool SharedLibrary::DependencyIterator::GetNext() {
546  dep_name_ = NULL;
547  for (; iter_.HasNext(); iter_.GetNext()) {
548    if (iter_.GetTag() == DT_NEEDED) {
549      dep_name_ = symbols_->GetStringById(iter_.GetValue());
550      iter_.GetNext();
551      return true;
552    }
553  }
554  return false;
555}
556
557}  // namespace crazy
558