• 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 // Implements the crazy linker C-based API exposed by <crazy_linker.h>
6 
7 #include <crazy_linker.h>
8 
9 #include <string.h>
10 
11 #include "crazy_linker_error.h"
12 #include "crazy_linker_ashmem.h"
13 #include "crazy_linker_globals.h"
14 #include "crazy_linker_proc_maps.h"
15 #include "crazy_linker_search_path_list.h"
16 #include "crazy_linker_shared_library.h"
17 #include "crazy_linker_thread.h"
18 #include "crazy_linker_util.h"
19 #include "crazy_linker_library_view.h"
20 #include "crazy_linker_system.h"
21 
22 using crazy::Globals;
23 using crazy::Error;
24 using crazy::SearchPathList;
25 using crazy::ScopedGlobalLock;
26 using crazy::LibraryView;
27 
28 //
29 // crazy_context_t
30 //
31 
32 struct crazy_context_t {
33  public:
crazy_context_tcrazy_context_t34   crazy_context_t()
35       : load_address(0),
36         file_offset(0),
37         error(),
38         search_paths(),
39         java_vm(NULL),
40         minimum_jni_version(0),
41         callback_poster(NULL),
42         callback_poster_opaque(NULL) {
43     ResetSearchPaths();
44   }
45 
46   void ResetSearchPaths();
47 
48   size_t load_address;
49   size_t file_offset;
50   Error error;
51   SearchPathList search_paths;
52   void* java_vm;
53   int minimum_jni_version;
54   crazy_callback_poster_t callback_poster;
55   void* callback_poster_opaque;
56 };
57 
ResetSearchPaths()58 void crazy_context_t::ResetSearchPaths() {
59   search_paths.ResetFromEnv("LD_LIBRARY_PATH");
60 }
61 
62 //
63 // API functions
64 //
65 
66 extern "C" {
67 
crazy_context_create(void)68 crazy_context_t* crazy_context_create(void) { return new crazy_context_t(); }
69 
crazy_context_get_error(crazy_context_t * context)70 const char* crazy_context_get_error(crazy_context_t* context) {
71   const char* error = context->error.c_str();
72   return (error[0] != '\0') ? error : NULL;
73 }
74 
75 // Clear error in a given context.
crazy_context_clear_error(crazy_context_t * context)76 void crazy_context_clear_error(crazy_context_t* context) {
77   context->error = "";
78 }
79 
crazy_context_set_load_address(crazy_context_t * context,size_t load_address)80 void crazy_context_set_load_address(crazy_context_t* context,
81                                     size_t load_address) {
82   context->load_address = load_address;
83 }
84 
crazy_context_get_load_address(crazy_context_t * context)85 size_t crazy_context_get_load_address(crazy_context_t* context) {
86   return context->load_address;
87 }
88 
crazy_context_set_file_offset(crazy_context_t * context,size_t file_offset)89 void crazy_context_set_file_offset(crazy_context_t* context,
90                                    size_t file_offset) {
91   context->file_offset = file_offset;
92 }
93 
crazy_context_get_file_offset(crazy_context_t * context)94 size_t crazy_context_get_file_offset(crazy_context_t* context) {
95   return context->file_offset;
96 }
97 
crazy_context_add_search_path(crazy_context_t * context,const char * file_path)98 crazy_status_t crazy_context_add_search_path(crazy_context_t* context,
99                                              const char* file_path) {
100   context->search_paths.AddPaths(file_path);
101   return CRAZY_STATUS_SUCCESS;
102 }
103 
crazy_context_add_search_path_for_address(crazy_context_t * context,void * address)104 crazy_status_t crazy_context_add_search_path_for_address(
105     crazy_context_t* context,
106     void* address) {
107   uintptr_t load_address;
108   char path[512];
109   char* p;
110 
111   if (crazy::FindElfBinaryForAddress(
112           address, &load_address, path, sizeof(path)) &&
113       (p = strrchr(path, '/')) != NULL && p[1]) {
114     *p = '\0';
115     return crazy_context_add_search_path(context, path);
116   }
117 
118   context->error.Format("Could not find ELF binary at address @%p", address);
119   return CRAZY_STATUS_FAILURE;
120 }
121 
crazy_context_reset_search_paths(crazy_context_t * context)122 void crazy_context_reset_search_paths(crazy_context_t* context) {
123   context->ResetSearchPaths();
124 }
125 
crazy_context_set_java_vm(crazy_context_t * context,void * java_vm,int minimum_jni_version)126 void crazy_context_set_java_vm(crazy_context_t* context,
127                                void* java_vm,
128                                int minimum_jni_version) {
129   context->java_vm = java_vm;
130   context->minimum_jni_version = minimum_jni_version;
131 }
132 
crazy_context_get_java_vm(crazy_context_t * context,void ** java_vm,int * minimum_jni_version)133 void crazy_context_get_java_vm(crazy_context_t* context,
134                                void** java_vm,
135                                int* minimum_jni_version) {
136   *java_vm = context->java_vm;
137   *minimum_jni_version = context->minimum_jni_version;
138 }
139 
crazy_context_set_callback_poster(crazy_context_t * context,crazy_callback_poster_t poster,void * poster_opaque)140 void crazy_context_set_callback_poster(crazy_context_t* context,
141                                        crazy_callback_poster_t poster,
142                                        void* poster_opaque) {
143   context->callback_poster = poster;
144   context->callback_poster_opaque = poster_opaque;
145 }
146 
crazy_context_get_callback_poster(crazy_context_t * context,crazy_callback_poster_t * poster,void ** poster_opaque)147 void crazy_context_get_callback_poster(crazy_context_t* context,
148                                        crazy_callback_poster_t* poster,
149                                        void** poster_opaque) {
150   *poster = context->callback_poster;
151   *poster_opaque = context->callback_poster_opaque;
152 }
153 
crazy_callback_run(crazy_callback_t * callback)154 void crazy_callback_run(crazy_callback_t* callback) {
155   (*callback->handler)(callback->opaque);
156 }
157 
crazy_context_destroy(crazy_context_t * context)158 void crazy_context_destroy(crazy_context_t* context) { delete context; }
159 
160 // Scoped delayed execution, removes RDebug callbacks on scope exit.  No-op
161 // if callback is NULL.
162 class ScopedDelayedCallbackPoster {
163  public:
ScopedDelayedCallbackPoster(crazy_context_t * context)164   ScopedDelayedCallbackPoster(crazy_context_t* context) {
165     if (context && context->callback_poster) {
166       crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(&PostFromContext,
167                                                             context);
168       set_delayed_callback_poster_ = true;
169     } else {
170       set_delayed_callback_poster_ = false;
171     }
172   }
173 
~ScopedDelayedCallbackPoster()174   ~ScopedDelayedCallbackPoster() {
175     if (set_delayed_callback_poster_)
176       crazy::Globals::GetRDebug()->SetDelayedCallbackPoster(NULL, NULL);
177   }
178 
179  private:
180   // Wrap callback hander and opaque into a call to a crazy_context_poster_t.
PostFromContext(void * crazy_context,crazy_callback_handler_t handler,void * opaque)181   static bool PostFromContext(void* crazy_context,
182                               crazy_callback_handler_t handler,
183                               void* opaque) {
184     crazy_context_t* context = static_cast<crazy_context_t*>(crazy_context);
185     crazy_callback_t callback;
186     callback.handler = handler;
187     callback.opaque = opaque;
188     return context->callback_poster(&callback,
189                                     context->callback_poster_opaque);
190   }
191 
192   // True if the context offered a callback_poster, otherwise false.
193   bool set_delayed_callback_poster_;
194 };
195 
crazy_library_open(crazy_library_t ** library,const char * lib_name,crazy_context_t * context)196 crazy_status_t crazy_library_open(crazy_library_t** library,
197                                   const char* lib_name,
198                                   crazy_context_t* context) {
199   ScopedDelayedCallbackPoster poster(context);
200   ScopedGlobalLock lock;
201 
202   LibraryView* wrap =
203       crazy::Globals::GetLibraries()->LoadLibrary(lib_name,
204                                                   RTLD_NOW,
205                                                   context->load_address,
206                                                   context->file_offset,
207                                                   &context->search_paths,
208                                                   &context->error);
209 
210   if (!wrap)
211     return CRAZY_STATUS_FAILURE;
212 
213   if (context->java_vm != NULL && wrap->IsCrazy()) {
214     crazy::SharedLibrary* lib = wrap->GetCrazy();
215     if (!lib->SetJavaVM(
216              context->java_vm, context->minimum_jni_version, &context->error)) {
217       crazy::Globals::GetLibraries()->UnloadLibrary(wrap);
218       return CRAZY_STATUS_FAILURE;
219     }
220   }
221 
222   *library = reinterpret_cast<crazy_library_t*>(wrap);
223   return CRAZY_STATUS_SUCCESS;
224 }
225 
crazy_library_get_info(crazy_library_t * library,crazy_context_t * context,crazy_library_info_t * info)226 crazy_status_t crazy_library_get_info(crazy_library_t* library,
227                                       crazy_context_t* context,
228                                       crazy_library_info_t* info) {
229   if (!library) {
230     context->error = "Invalid library file handle";
231     return CRAZY_STATUS_FAILURE;
232   }
233 
234   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
235   if (!wrap->GetInfo(&info->load_address,
236                      &info->load_size,
237                      &info->relro_start,
238                      &info->relro_size,
239                      &context->error)) {
240     return CRAZY_STATUS_FAILURE;
241   }
242 
243   return CRAZY_STATUS_SUCCESS;
244 }
245 
crazy_system_can_share_relro(void)246 crazy_status_t crazy_system_can_share_relro(void) {
247   crazy::AshmemRegion region;
248   if (!region.Allocate(PAGE_SIZE, NULL) ||
249       !region.SetProtectionFlags(PROT_READ) ||
250       !crazy::AshmemRegion::CheckFileDescriptorIsReadOnly(region.fd()))
251     return CRAZY_STATUS_FAILURE;
252 
253   return CRAZY_STATUS_SUCCESS;
254 }
255 
crazy_library_create_shared_relro(crazy_library_t * library,crazy_context_t * context,size_t load_address,size_t * relro_start,size_t * relro_size,int * relro_fd)256 crazy_status_t crazy_library_create_shared_relro(crazy_library_t* library,
257                                                  crazy_context_t* context,
258                                                  size_t load_address,
259                                                  size_t* relro_start,
260                                                  size_t* relro_size,
261                                                  int* relro_fd) {
262   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
263 
264   if (!library || !wrap->IsCrazy()) {
265     context->error = "Invalid library file handle";
266     return CRAZY_STATUS_FAILURE;
267   }
268 
269   crazy::SharedLibrary* lib = wrap->GetCrazy();
270   if (!lib->CreateSharedRelro(
271            load_address, relro_start, relro_size, relro_fd, &context->error))
272     return CRAZY_STATUS_FAILURE;
273 
274   return CRAZY_STATUS_SUCCESS;
275 }
276 
crazy_library_use_shared_relro(crazy_library_t * library,crazy_context_t * context,size_t relro_start,size_t relro_size,int relro_fd)277 crazy_status_t crazy_library_use_shared_relro(crazy_library_t* library,
278                                               crazy_context_t* context,
279                                               size_t relro_start,
280                                               size_t relro_size,
281                                               int relro_fd) {
282   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
283 
284   if (!library || !wrap->IsCrazy()) {
285     context->error = "Invalid library file handle";
286     return CRAZY_STATUS_FAILURE;
287   }
288 
289   crazy::SharedLibrary* lib = wrap->GetCrazy();
290   if (!lib->UseSharedRelro(relro_start, relro_size, relro_fd, &context->error))
291     return CRAZY_STATUS_FAILURE;
292 
293   return CRAZY_STATUS_SUCCESS;
294 }
295 
crazy_library_find_by_name(const char * library_name,crazy_library_t ** library)296 crazy_status_t crazy_library_find_by_name(const char* library_name,
297                                           crazy_library_t** library) {
298   {
299     ScopedGlobalLock lock;
300     LibraryView* wrap =
301         Globals::GetLibraries()->FindLibraryByName(library_name);
302     if (!wrap)
303       return CRAZY_STATUS_FAILURE;
304 
305     wrap->AddRef();
306     *library = reinterpret_cast<crazy_library_t*>(wrap);
307   }
308   return CRAZY_STATUS_SUCCESS;
309 }
310 
crazy_library_find_symbol(crazy_library_t * library,const char * symbol_name,void ** symbol_address)311 crazy_status_t crazy_library_find_symbol(crazy_library_t* library,
312                                          const char* symbol_name,
313                                          void** symbol_address) {
314   LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
315 
316   // TODO(digit): Handle NULL symbols properly.
317   *symbol_address = wrap->LookupSymbol(symbol_name);
318   return (*symbol_address == NULL) ? CRAZY_STATUS_FAILURE
319                                    : CRAZY_STATUS_SUCCESS;
320 }
321 
crazy_linker_find_symbol(const char * symbol_name,void ** symbol_address)322 crazy_status_t crazy_linker_find_symbol(const char* symbol_name,
323                                         void** symbol_address) {
324   // TODO(digit): Implement this.
325   return CRAZY_STATUS_FAILURE;
326 }
327 
crazy_library_find_from_address(void * address,crazy_library_t ** library)328 crazy_status_t crazy_library_find_from_address(void* address,
329                                                crazy_library_t** library) {
330   {
331     ScopedGlobalLock lock;
332     LibraryView* wrap = Globals::GetLibraries()->FindLibraryForAddress(address);
333     if (!wrap)
334       return CRAZY_STATUS_FAILURE;
335 
336     wrap->AddRef();
337 
338     *library = reinterpret_cast<crazy_library_t*>(wrap);
339     return CRAZY_STATUS_SUCCESS;
340   }
341 }
342 
crazy_library_close(crazy_library_t * library)343 void crazy_library_close(crazy_library_t* library) {
344   crazy_library_close_with_context(library, NULL);
345 }
346 
crazy_library_close_with_context(crazy_library_t * library,crazy_context_t * context)347 void crazy_library_close_with_context(crazy_library_t* library,
348                                       crazy_context_t* context) {
349   if (library) {
350     ScopedDelayedCallbackPoster poster(context);
351     ScopedGlobalLock lock;
352     LibraryView* wrap = reinterpret_cast<LibraryView*>(library);
353 
354     Globals::GetLibraries()->UnloadLibrary(wrap);
355   }
356 }
357 
358 }  // extern "C"
359