crazy_linker_shared_library.cpp revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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#if defined(__arm__) || defined(__aarch64__)
67
68#define DT_ANDROID_REL_OFFSET (DT_LOOS)
69#define DT_ANDROID_REL_SIZE (DT_LOOS + 1)
70
71#endif  // __arm__ || __aarch64__
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#if defined(__arm__) || defined(__aarch64__)
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 packed relocations section.
185// Returns an allocated buffer holding the data, or NULL on error.
186uint8_t* ReadPackedRelocations(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__ || __aarch64__
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#if defined(__arm__) || defined(__aarch64__)
224  delete [] packed_relocations_;
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#endif
280
281#if defined(__arm__) || defined(__aarch64__)
282  off_t packed_relocations_offset = 0;
283  size_t packed_relocations_size = 0;
284#endif
285
286  LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_);
287  ElfView::DynamicIterator dyn(&view_);
288  for (; dyn.HasNext(); dyn.GetNext()) {
289    ELF::Addr dyn_value = dyn.GetValue();
290    uintptr_t dyn_addr = dyn.GetAddress(load_bias());
291    switch (dyn.GetTag()) {
292      case DT_DEBUG:
293        if (view_.dynamic_flags() & PF_W) {
294          *dyn.GetValuePointer() =
295              reinterpret_cast<uintptr_t>(Globals::GetRDebug()->GetAddress());
296        }
297        break;
298      case DT_INIT:
299        LOG("  DT_INIT addr=%p\n", dyn_addr);
300        init_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
301        break;
302      case DT_FINI:
303        LOG("  DT_FINI addr=%p\n", dyn_addr);
304        fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
305        break;
306      case DT_INIT_ARRAY:
307        LOG("  DT_INIT_ARRAY addr=%p\n", dyn_addr);
308        init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
309        break;
310      case DT_INIT_ARRAYSZ:
311        init_array_count_ = dyn_value / sizeof(ELF::Addr);
312        LOG("  DT_INIT_ARRAYSZ value=%p count=%p\n",
313            dyn_value,
314            init_array_count_);
315        break;
316      case DT_FINI_ARRAY:
317        LOG("  DT_FINI_ARRAY addr=%p\n", dyn_addr);
318        fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
319        break;
320      case DT_FINI_ARRAYSZ:
321        fini_array_count_ = dyn_value / sizeof(ELF::Addr);
322        LOG("  DT_FINI_ARRAYSZ value=%p count=%p\n",
323            dyn_value,
324            fini_array_count_);
325        break;
326      case DT_PREINIT_ARRAY:
327        LOG("  DT_PREINIT_ARRAY addr=%p\n", dyn_addr);
328        preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
329        break;
330      case DT_PREINIT_ARRAYSZ:
331        preinit_array_count_ = dyn_value / sizeof(ELF::Addr);
332        LOG("  DT_PREINIT_ARRAYSZ value=%p count=%p\n",
333            dyn_value,
334            preinit_array_count_);
335        break;
336      case DT_SYMBOLIC:
337        LOG("  DT_SYMBOLIC\n");
338        has_DT_SYMBOLIC_ = true;
339        break;
340      case DT_FLAGS:
341        if (dyn_value & DF_SYMBOLIC)
342          has_DT_SYMBOLIC_ = true;
343        break;
344#if defined(__arm__) || defined(__aarch64__)
345      case DT_ANDROID_REL_OFFSET:
346        packed_relocations_offset = dyn.GetOffset();
347        LOG("  DT_ANDROID_REL_OFFSET addr=%p\n", packed_relocations_offset);
348        break;
349      case DT_ANDROID_REL_SIZE:
350        packed_relocations_size = dyn.GetValue();
351        LOG("  DT_ANDROID_REL_SIZE=%d\n", packed_relocations_size);
352        break;
353#endif
354#if defined(__mips__)
355      case DT_MIPS_RLD_MAP:
356        *dyn.GetValuePointer() =
357            reinterpret_cast<ELF::Addr>(Globals::GetRDebug()->GetAddress());
358        break;
359#endif
360      default:
361        ;
362    }
363  }
364
365#if defined(__arm__) || defined(__aarch64__)
366  // If packed relocations are present in the target library, read the
367  // section data and save it in packed_relocations_.
368  if (packed_relocations_offset && packed_relocations_size) {
369    LOG("%s: Packed relocations found at offset %d, %d bytes\n",
370        __FUNCTION__,
371        packed_relocations_offset,
372        packed_relocations_size);
373
374    packed_relocations_ =
375        ReadPackedRelocations(full_path,
376                              packed_relocations_offset + file_offset,
377                              packed_relocations_size,
378                              error);
379    if (!packed_relocations_)
380      return false;
381
382    LOG("%s: Packed relocations stored at %p\n",
383        __FUNCTION__,
384        packed_relocations_);
385  }
386#endif
387
388  LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_);
389  return true;
390}
391
392bool SharedLibrary::Relocate(LibraryList* lib_list,
393                             Vector<LibraryView*>* dependencies,
394                             Error* error) {
395  // Apply relocations.
396  LOG("%s: Applying relocations to %s\n", __FUNCTION__, base_name_);
397
398  ElfRelocations relocations;
399
400  if (!relocations.Init(&view_, error))
401    return false;
402
403#if defined(__arm__) || defined(__aarch64__)
404  relocations.RegisterPackedRelocations(packed_relocations_);
405#endif
406
407  SharedLibraryResolver resolver(this, lib_list, dependencies);
408  if (!relocations.ApplyAll(&symbols_, &resolver, error))
409    return false;
410
411  LOG("%s: Relocations applied for %s\n", __FUNCTION__, base_name_);
412  return true;
413}
414
415const ELF::Sym* SharedLibrary::LookupSymbolEntry(const char* symbol_name) {
416  return symbols_.LookupByName(symbol_name);
417}
418
419void* SharedLibrary::FindAddressForSymbol(const char* symbol_name) {
420  return symbols_.LookupAddressByName(symbol_name, view_.load_bias());
421}
422
423bool SharedLibrary::CreateSharedRelro(size_t load_address,
424                                      size_t* relro_start,
425                                      size_t* relro_size,
426                                      int* relro_fd,
427                                      Error* error) {
428  SharedRelro relro;
429
430  if (!relro.Allocate(relro_size_, base_name_, error))
431    return false;
432
433  if (load_address != 0 && load_address != this->load_address()) {
434    // Need to relocate the content of the ashmem region first to accomodate
435    // for the new load address.
436    if (!relro.CopyFromRelocated(
437             &view_, load_address, relro_start_, relro_size_, error))
438      return false;
439  } else {
440    // Simply copy, no relocations.
441    if (!relro.CopyFrom(relro_start_, relro_size_, error))
442      return false;
443  }
444
445  // Enforce read-only mode for the region's content.
446  if (!relro.ForceReadOnly(error))
447    return false;
448
449  // All good.
450  *relro_start = relro.start();
451  *relro_size = relro.size();
452  *relro_fd = relro.DetachFd();
453  return true;
454}
455
456bool SharedLibrary::UseSharedRelro(size_t relro_start,
457                                   size_t relro_size,
458                                   int relro_fd,
459                                   Error* error) {
460  LOG("%s: relro_start=%p relro_size=%p relro_fd=%d\n",
461      __FUNCTION__,
462      (void*)relro_start,
463      (void*)relro_size,
464      relro_fd);
465
466  if (relro_fd < 0 || relro_size == 0) {
467    // Nothing to do here.
468    return true;
469  }
470
471  // Sanity check: A shared RELRO is not already used.
472  if (relro_used_) {
473    *error = "Library already using shared RELRO section";
474    return false;
475  }
476
477  // Sanity check: RELRO addresses must match.
478  if (relro_start_ != relro_start || relro_size_ != relro_size) {
479    error->Format("RELRO mismatch addr=%p size=%p (wanted addr=%p size=%p)",
480                  relro_start_,
481                  relro_size_,
482                  relro_start,
483                  relro_size);
484    return false;
485  }
486
487  // Everything's good, swap pages in this process's address space.
488  SharedRelro relro;
489  if (!relro.InitFrom(relro_start, relro_size, relro_fd, error))
490    return false;
491
492  relro_used_ = true;
493  return true;
494}
495
496void SharedLibrary::CallConstructors() {
497  CallFunction(init_func_, "DT_INIT");
498  for (size_t n = 0; n < init_array_count_; ++n)
499    CallFunction(init_array_[n], "DT_INIT_ARRAY");
500}
501
502void SharedLibrary::CallDestructors() {
503  for (size_t n = fini_array_count_; n > 0; --n) {
504    CallFunction(fini_array_[n - 1], "DT_FINI_ARRAY");
505  }
506  CallFunction(fini_func_, "DT_FINI");
507}
508
509bool SharedLibrary::SetJavaVM(void* java_vm,
510                              int minimum_jni_version,
511                              Error* error) {
512  if (java_vm == NULL)
513    return true;
514
515  // Lookup for JNI_OnLoad, exit if it doesn't exist.
516  JNI_OnLoadFunctionPtr jni_onload = reinterpret_cast<JNI_OnLoadFunctionPtr>(
517      FindAddressForSymbol("JNI_OnLoad"));
518  if (!jni_onload)
519    return true;
520
521  int jni_version = (*jni_onload)(java_vm, NULL);
522  if (jni_version < minimum_jni_version) {
523    error->Format("JNI_OnLoad() in %s returned %d, expected at least %d",
524                  full_path_,
525                  jni_version,
526                  minimum_jni_version);
527    return false;
528  }
529
530  // Save the JavaVM handle for unload time.
531  java_vm_ = java_vm;
532  return true;
533}
534
535void SharedLibrary::CallJniOnUnload() {
536  if (!java_vm_)
537    return;
538
539  JNI_OnUnloadFunctionPtr jni_on_unload =
540      reinterpret_cast<JNI_OnUnloadFunctionPtr>(
541          this->FindAddressForSymbol("JNI_OnUnload"));
542
543  if (jni_on_unload)
544    (*jni_on_unload)(java_vm_, NULL);
545}
546
547bool SharedLibrary::DependencyIterator::GetNext() {
548  dep_name_ = NULL;
549  for (; iter_.HasNext(); iter_.GetNext()) {
550    if (iter_.GetTag() == DT_NEEDED) {
551      dep_name_ = symbols_->GetStringById(iter_.GetValue());
552      iter_.GetNext();
553      return true;
554    }
555  }
556  return false;
557}
558
559}  // namespace crazy
560