• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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...).
CallFunction(linker_function_t func,const char * func_type)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:
SharedLibraryResolver(SharedLibrary * lib,LibraryList * lib_list,Vector<LibraryView * > * dependencies)87   SharedLibraryResolver(SharedLibrary* lib,
88                         LibraryList* lib_list,
89                         Vector<LibraryView*>* dependencies)
90       : lib_(lib), dependencies_(dependencies) {}
91 
Lookup(const char * symbol_name)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 
SharedLibrary()153 SharedLibrary::SharedLibrary() { ::memset(this, 0, sizeof(*this)); }
154 
~SharedLibrary()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 
Load(const char * full_path,size_t load_address,size_t file_offset,Error * error)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 
Relocate(LibraryList * lib_list,Vector<LibraryView * > * dependencies,Error * error)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 
LookupSymbolEntry(const char * symbol_name)306 const ELF::Sym* SharedLibrary::LookupSymbolEntry(const char* symbol_name) {
307   return symbols_.LookupByName(symbol_name);
308 }
309 
FindAddressForSymbol(const char * symbol_name)310 void* SharedLibrary::FindAddressForSymbol(const char* symbol_name) {
311   return symbols_.LookupAddressByName(symbol_name, view_.load_bias());
312 }
313 
CreateSharedRelro(size_t load_address,size_t * relro_start,size_t * relro_size,int * relro_fd,Error * error)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 
UseSharedRelro(size_t relro_start,size_t relro_size,int relro_fd,Error * error)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 
CallConstructors()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 
CallDestructors()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 
SetJavaVM(void * java_vm,int minimum_jni_version,Error * error)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 
CallJniOnUnload()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 
GetNext()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