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