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