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 #ifndef CRAZY_LINKER_H 6 #define CRAZY_LINKER_H 7 8 // This is the crazy linker, a custom dynamic linker that can be used 9 // by NDK applications to load shared libraries (not executables) with 10 // a twist. 11 // 12 // Compared to the dynamic linker, the crazy one has the following 13 // features: 14 // 15 // - It can use an arbitrary search path. 16 // 17 // - It can load a library at a memory fixed address, or from a fixed 18 // file offset (both must be page-aligned). 19 // 20 // - It can share the RELRO section between two libraries 21 // loaded at the same address in two distinct processes. 22 // 23 #include <dlfcn.h> 24 #include <stdbool.h> 25 #include <stddef.h> 26 27 #ifdef __cplusplus 28 extern "C" { 29 #endif 30 31 // Function attribute to indicate that it needs to be exported by 32 // the library. 33 #define _CRAZY_PUBLIC __attribute__((__visibility__("default"))) 34 35 // Status values returned by crazy linker functions to indicate 36 // success or failure. They were chosen to match boolean values, 37 // this allows one to test for failures with: 38 // 39 // if (!crazy_linker_function(....)) { 40 // ... an error occured. 41 // } 42 // 43 // If the function called used a crazy_context_t, it is possible to 44 // retrieve the error details with crazy_context_get_error(). 45 typedef enum { 46 CRAZY_STATUS_FAILURE = 0, 47 CRAZY_STATUS_SUCCESS = 1 48 } crazy_status_t; 49 50 // Opaque handle to a context object that will hold parameters 51 // for the crazy linker's operations. For example, this is where 52 // you would set the explicit load address, and other user-provided 53 // values before calling functions like crazy_library_open(). 54 // 55 // The context holds a list of library search paths, initialized to 56 // the content of the LD_LIBRARY_PATH variable on creation. 57 // 58 // The context also holds a string buffer to hold error messages that 59 // can be queried with crazy_context_get_error(). 60 typedef struct crazy_context_t crazy_context_t; 61 62 // Create a new context object. 63 // Note that this calls crazy_context_reset_search_paths(). 64 crazy_context_t* crazy_context_create(void) _CRAZY_PUBLIC; 65 66 // Return current error string, or NULL if there was no error. 67 const char* crazy_context_get_error(crazy_context_t* context) _CRAZY_PUBLIC; 68 69 // Clear error in a given context. 70 void crazy_context_clear_error(crazy_context_t* context) _CRAZY_PUBLIC; 71 72 // Set the explicit load address in a context object. Value 0 means 73 // the address is randomized. 74 void crazy_context_set_load_address(crazy_context_t* context, 75 size_t load_address) _CRAZY_PUBLIC; 76 77 // Return the current load address in a context. 78 size_t crazy_context_get_load_address(crazy_context_t* context) _CRAZY_PUBLIC; 79 80 // Set the explicit file offset in a context object. The value should 81 // always page-aligned, or the load will fail. 82 // Note you can not use the same file with multiple offsets. See crbug/388223. 83 void crazy_context_set_file_offset(crazy_context_t* context, 84 size_t file_offset) _CRAZY_PUBLIC; 85 86 // Return the current file offset in a context object. 87 size_t crazy_context_get_file_offset(crazy_context_t* context); 88 89 // Add one or more paths to the list of library search paths held 90 // by a given context. |path| is a string using a column (:) as a 91 // list separator. As with the PATH variable, an empty list item 92 // is equivalent to '.', the current directory. 93 // This can fail if too many paths are added to the context. 94 // 95 // NOTE: Calling this function appends new paths to the search list, 96 // but all paths added with this function will be searched before 97 // the ones listed in LD_LIBRARY_PATH. 98 crazy_status_t crazy_context_add_search_path( 99 crazy_context_t* context, 100 const char* file_path) _CRAZY_PUBLIC; 101 102 // Find the ELF binary that contains |address|, and add its directory 103 // path to the context's list of search directories. This is useful to 104 // load libraries in the same directory than the current program itself. 105 crazy_status_t crazy_context_add_search_path_for_address( 106 crazy_context_t* context, 107 void* address) _CRAZY_PUBLIC; 108 109 // Reset the search paths to the value of the LD_LIBRARY_PATH 110 // environment variable. This essentially removes any paths 111 // that were added with crazy_context_add_search_path() or 112 // crazy_context_add_search_path_for_address(). 113 void crazy_context_reset_search_paths(crazy_context_t* context) _CRAZY_PUBLIC; 114 115 // Record the value of |java_vm| inside of |context|. If this is not NULL, 116 // which is the default, then after loading any library, the crazy linker 117 // will look for a "JNI_OnLoad" symbol within it, and, if it exists, will call 118 // it, passing the value of |java_vm| to it. If the function returns with 119 // a jni version number that is smaller than |minimum_jni_version|, then 120 // the library load will fail with an error. 121 // 122 // The |java_vm| field is also saved in the crazy_library_t object, and 123 // used at unload time to call JNI_OnUnload() if it exists. 124 void crazy_context_set_java_vm(crazy_context_t* context, 125 void* java_vm, 126 int minimum_jni_version); 127 128 // Retrieves the last values set with crazy_context_set_java_vm(). 129 // A value of NUMM in |*java_vm| means the feature is disabled. 130 void crazy_context_get_java_vm(crazy_context_t* context, 131 void** java_vm, 132 int* minimum_jni_version); 133 134 // Destroy a given context object. 135 void crazy_context_destroy(crazy_context_t* context) _CRAZY_PUBLIC; 136 137 // Some operations performed by the crazy linker might conflict with the 138 // system linker if they are used concurrently in different threads 139 // (e.g. modifying the list of shared libraries seen by GDB). To work 140 // around this, the crazy linker provides a way to delay these conflicting 141 // operations for a later time. 142 // 143 // This works by wrapping each of these operations in a small data structure 144 // (crazy_callback_t), which can later be passed to crazy_callback_run() 145 // to execute it. 146 // 147 // The user must provide a function to record these callbacks during 148 // library loading, by calling crazy_linker_set_callback_poster(). 149 // 150 // Once all libraries are loaded, the callbacks can be later called either 151 // in a different thread, or when it is safe to assume the system linker 152 // cannot be running in parallel. 153 154 // Callback handler. 155 typedef void (*crazy_callback_handler_t)(void* opaque); 156 157 // A small structure used to model a callback provided by the crazy linker. 158 // Use crazy_callback_run() to run the callback. 159 typedef struct { 160 crazy_callback_handler_t handler; 161 void* opaque; 162 } crazy_callback_t; 163 164 // Function to call to enable a callback into the crazy linker when delayed 165 // operations are enabled (see crazy_context_set_callback_poster). A call 166 // to crazy_callback_poster_t returns true if the callback was successfully 167 // set up and will occur later, false if callback could not be set up (and 168 // so will never occur). 169 typedef bool (*crazy_callback_poster_t)( 170 crazy_callback_t* callback, void* poster_opaque); 171 172 // Enable delayed operation, by passing the address of a 173 // |crazy_callback_poster_t| function, that will be called during library 174 // loading to let the user record callbacks for delayed operations. 175 // Callers must copy the |crazy_callback_t| passed to |poster|. 176 // |poster_opaque| is an opaque value for client code use, passed back 177 // on each call to |poster|. 178 // |poster| can be NULL to disable the feature. 179 void crazy_context_set_callback_poster(crazy_context_t* context, 180 crazy_callback_poster_t poster, 181 void* poster_opaque); 182 183 // Return the address of the function that the crazy linker can use to 184 // request callbacks, and the |poster_opaque| passed back on each call 185 // to |poster|. |poster| is NULL if the feature is disabled. 186 void crazy_context_get_callback_poster(crazy_context_t* context, 187 crazy_callback_poster_t* poster, 188 void** poster_opaque); 189 190 // Run a given |callback| in the current thread. Must only be called once 191 // per callback. 192 void crazy_callback_run(crazy_callback_t* callback); 193 194 // Opaque handle to a library as seen/loaded by the crazy linker. 195 typedef struct crazy_library_t crazy_library_t; 196 197 // Try to open or load a library with the crazy linker. 198 // |lib_name| if the library name or path. If it contains a directory 199 // separator (/), this is treated as a explicit file path, otherwise 200 // it is treated as a base name, and the context's search path list 201 // will be used to locate the corresponding file. 202 // |context| is a linker context handle. Can be NULL for defaults. 203 // On success, return CRAZY_STATUS_SUCCESS and sets |*library|. 204 // Libraries are reference-counted, trying to open the same library 205 // twice will return the same library handle. 206 // 207 // NOTE: The load address and file offset from the context only apply 208 // to the library being loaded (when not already in the process). If the 209 // operations needs to load any dependency libraries, these will use 210 // offset and address values of 0 to do so. 211 // 212 // NOTE: It is possible to open NDK system libraries (e.g. "liblog.so") 213 // with this function, but they will be loaded with the system dlopen(). 214 crazy_status_t crazy_library_open(crazy_library_t** library, 215 const char* lib_name, 216 crazy_context_t* context) _CRAZY_PUBLIC; 217 218 // Try to open or load a library with the crazy linker. The 219 // library is in a zip file with the name |zipfile_name|. Within the zip 220 // file the library must be uncompressed and page aligned. |zipfile_name| 221 // should be an absolute path name and |lib_name| should be a relative 222 // pathname. The library in the zip file is expected to have the name 223 // lib/<abi_tag>/crazy.<lib_name> where abi_tag is the abi directory matching 224 // the ABI for which the crazy linker was compiled. Note this does not support 225 // opening multiple libraries in the same zipfile, see crbug/388223. 226 crazy_status_t crazy_library_open_in_zip_file(crazy_library_t** library, 227 const char* zipfile_name, 228 const char* lib_name, 229 crazy_context_t* context) 230 _CRAZY_PUBLIC; 231 232 // A structure used to hold information about a given library. 233 // |load_address| is the library's actual (page-aligned) load address. 234 // |load_size| is the library's actual (page-aligned) size. 235 // |relro_start| is the address of the library's RELRO section in memory. 236 // |relso_size| is the size of the library's RELRO section (or 0 if none). 237 // |relro_fd| is the ashmem file descriptor for the shared section, if one 238 // was created with crazy_library_enable_relro_sharing(), -1 otherwise. 239 typedef struct { 240 size_t load_address; 241 size_t load_size; 242 size_t relro_start; 243 size_t relro_size; 244 } crazy_library_info_t; 245 246 // Retrieve information about a given library. 247 // |library| is a library handle. 248 // |context| will get an error message on failure. 249 // On success, return true and sets |*info|. 250 // Note that this function will fail for system libraries. 251 crazy_status_t crazy_library_get_info(crazy_library_t* library, 252 crazy_context_t* context, 253 crazy_library_info_t* info); 254 255 // Checks whether the system can support RELRO section sharing. This is 256 // mainly due to the fact that old Android kernel images have a bug in their 257 // implementation of Ashmem region mapping protection. 258 // If this function returns CRAZY_STATUS_FAILURE, then calls to 259 // crazy_library_enable_relro_sharing() will return a failure to prevent 260 // the exploitation of this security issue in your code. 261 crazy_status_t crazy_system_can_share_relro(void); 262 263 // Create an ashmem region containing a copy of the RELRO section for a given 264 // |library|. This can be used with crazy_library_use_shared_relro(). 265 // |load_address| can be specified as non-0 to ensure that the content of the 266 // ashmem region corresponds to a RELRO relocated for a new load address. 267 // on success, return CRAZY_STATUS_SUCCESS and sets |*relro_start| to the 268 // start of the RELRO section in memory, |*relro_size| to its size in bytes 269 // and |*relro_fd| to a file descriptor to a read-only ashmem region containing 270 // the data. On failure, return false and set error message in |context|. 271 // NOTE: On success, the caller becomes the owner of |*relro_fd| and is shall 272 // close it appropriately. 273 crazy_status_t crazy_library_create_shared_relro(crazy_library_t* library, 274 crazy_context_t* context, 275 size_t load_address, 276 size_t* relro_start, 277 size_t* relro_size, 278 int* relro_fd) _CRAZY_PUBLIC; 279 280 // Use the shared RELRO section of the same library loaded in a different 281 // address space. On success, return CRAZY_STATUS_SUCCESS and owns |relro_fd|. 282 // On failure, return CRAZY_STATUS_FAILURE and sets error message in |context|. 283 // |library| is the library handle. 284 // |relro_start| is the address of the RELRO section in memory. 285 // |relro_size| is the size of the RELRO section. 286 // |relro_fd| is the file descriptor for the shared RELRO ashmem region. 287 // |context| will receive an error in case of failure. 288 // NOTE: This will fail if this is a system library, or if the RELRO 289 // parameters do not match the library's actual load address. 290 // NOTE: The caller is responsible for closing the file descriptor after this 291 // call. 292 crazy_status_t crazy_library_use_shared_relro(crazy_library_t* library, 293 crazy_context_t* context, 294 size_t relro_start, 295 size_t relro_size, 296 int relro_fd) _CRAZY_PUBLIC; 297 298 // Look for a library named |library_name| in the set of currently 299 // loaded libraries, and return a handle for it in |*library| on success. 300 // Note that this increments the reference count on the library, thus 301 // the caller shall call crazy_library_close() when it's done with it. 302 crazy_status_t crazy_library_find_by_name(const char* library_name, 303 crazy_library_t** library); 304 305 // Find the library that contains a given |address| in memory. 306 // On success, return CRAZY_STATUS_SUCCESS and sets |*library|. 307 crazy_status_t crazy_linker_find_library_from_address( 308 void* address, 309 crazy_library_t** library) _CRAZY_PUBLIC; 310 311 // Lookup a symbol's address by its |symbol_name| in a given library. 312 // This only looks at the symbols in |library|. 313 // On success, returns CRAZY_STATUS_SUCCESS and sets |*symbol_address|, 314 // which could be NULL for some symbols. 315 crazy_status_t crazy_library_find_symbol(crazy_library_t* library, 316 const char* symbol_name, 317 void** symbol_address) _CRAZY_PUBLIC; 318 319 // Lookup a symbol's address in all libraries known by the crazy linker. 320 // |symbol_name| is the symbol name. On success, returns CRAZY_STATUS_SUCCESS 321 // and sets |*symbol_address|. 322 // NOTE: This will _not_ look into system libraries that were not opened 323 // with the crazy linker. 324 crazy_status_t crazy_linker_find_symbol(const char* symbol_name, 325 void** symbol_address) _CRAZY_PUBLIC; 326 327 // Find the in-process library that contains a given memory address. 328 // Note that this works even if the memory is inside a system library that 329 // was not previously opened with crazy_library_open(). 330 // |address| is the memory address. 331 // On success, returns CRAZY_STATUS_SUCCESS and sets |*library|. 332 // The caller muyst call crazy_library_close() once it's done with the 333 // library. 334 crazy_status_t crazy_library_find_from_address( 335 void* address, 336 crazy_library_t** library) _CRAZY_PUBLIC; 337 338 // Close a library. This decrements its reference count. If it reaches 339 // zero, the library be unloaded from the process. 340 void crazy_library_close(crazy_library_t* library) _CRAZY_PUBLIC; 341 342 // Close a library, with associated context to support delayed operations. 343 void crazy_library_close_with_context(crazy_library_t* library, 344 crazy_context_t* context) _CRAZY_PUBLIC; 345 346 #ifdef __cplusplus 347 } /* extern "C" */ 348 #endif 349 350 #endif /* CRAZY_LINKER_H */ 351