Home | History | Annotate | Download | only in include
      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