tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

secload.c (6278B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "secport.h"
      6 #include "nspr.h"
      7 
      8 #ifdef XP_UNIX
      9 #include <unistd.h>
     10 #define BL_MAXSYMLINKS 20
     11 
     12 /*
     13 * If 'link' is a symbolic link, this function follows the symbolic links
     14 * and returns the pathname of the ultimate source of the symbolic links.
     15 * If 'link' is not a symbolic link, this function returns NULL.
     16 * The caller should call PR_Free to free the string returned by this
     17 * function.
     18 */
     19 static char*
     20 loader_GetOriginalPathname(const char* link)
     21 {
     22    char* resolved = NULL;
     23    char* input = NULL;
     24    PRUint32 iterations = 0;
     25    PRInt32 len = 0, retlen = 0;
     26    if (!link) {
     27        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     28        return NULL;
     29    }
     30    len = PR_MAX(1024, strlen(link) + 1);
     31    resolved = PR_Malloc(len);
     32    input = PR_Malloc(len);
     33    if (!resolved || !input) {
     34        if (resolved) {
     35            PR_Free(resolved);
     36        }
     37        if (input) {
     38            PR_Free(input);
     39        }
     40        return NULL;
     41    }
     42    strcpy(input, link);
     43    while ((iterations++ < BL_MAXSYMLINKS) &&
     44           ((retlen = readlink(input, resolved, len - 1)) > 0)) {
     45        char* tmp = input;
     46        resolved[retlen] = '\0'; /* NULL termination */
     47        input = resolved;
     48        resolved = tmp;
     49    }
     50    PR_Free(resolved);
     51    if (iterations == 1 && retlen < 0) {
     52        PR_Free(input);
     53        input = NULL;
     54    }
     55    return input;
     56 }
     57 #endif /* XP_UNIX */
     58 
     59 /*
     60 * Load the library with the file name 'name' residing in the same
     61 * directory as the reference library, whose pathname is 'referencePath'.
     62 */
     63 static PRLibrary*
     64 loader_LoadLibInReferenceDir(const char* referencePath, const char* name)
     65 {
     66    PRLibrary* dlh = NULL;
     67    char* fullName = NULL;
     68    char* c;
     69    PRLibSpec libSpec;
     70 
     71    /* Remove the trailing filename from referencePath and add the new one */
     72    c = strrchr(referencePath, PR_GetDirectorySeparator());
     73    if (c) {
     74        size_t referencePathSize = 1 + c - referencePath;
     75        fullName = (char*)PORT_Alloc(strlen(name) + referencePathSize + 1);
     76        if (fullName) {
     77            memcpy(fullName, referencePath, referencePathSize);
     78            strcpy(fullName + referencePathSize, name);
     79 #ifdef DEBUG_LOADER
     80            PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n",
     81                       fullName);
     82 #endif
     83            libSpec.type = PR_LibSpec_Pathname;
     84            libSpec.value.pathname = fullName;
     85            dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL
     86 #ifdef PR_LD_ALT_SEARCH_PATH
     87                                                       /* allow library's dependencies to be found in the same directory
     88                                                        * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */
     89                                                       | PR_LD_ALT_SEARCH_PATH
     90 #endif
     91            );
     92            PORT_Free(fullName);
     93        }
     94    }
     95    return dlh;
     96 }
     97 
     98 /*
     99 * Load a shared library called "newShLibName" in the same directory as
    100 * a shared library that is already loaded, called existingShLibName.
    101 * A pointer to a static function in that shared library,
    102 * staticShLibFunc, is required.
    103 *
    104 * existingShLibName:
    105 *   The file name of the shared library that shall be used as the
    106 *   "reference library". The loader will attempt to load the requested
    107 *   library from the same directory as the reference library.
    108 *
    109 * staticShLibFunc:
    110 *   Pointer to a static function in the "reference library".
    111 *
    112 * newShLibName:
    113 *   The simple file name of the new shared library to be loaded.
    114 *
    115 * We use PR_GetLibraryFilePathname to get the pathname of the loaded
    116 * shared lib that contains this function, and then do a
    117 * PR_LoadLibraryWithFlags with an absolute pathname for the shared
    118 * library to be loaded.
    119 *
    120 * On Windows, the "alternate search path" strategy is employed, if available.
    121 * On Unix, if existingShLibName is a symbolic link, and no link exists for the
    122 * new library, the original link will be resolved, and the new library loaded
    123 * from the resolved location.
    124 *
    125 * If the new shared library is not found in the same location as the reference
    126 * library, it will then be loaded from the normal system library path.
    127 *
    128 */
    129 
    130 PRLibrary*
    131 PORT_LoadLibraryFromOrigin(const char* existingShLibName,
    132                           PRFuncPtr staticShLibFunc,
    133                           const char* newShLibName)
    134 {
    135    PRLibrary* lib = NULL;
    136    char* fullPath = NULL;
    137    PRLibSpec libSpec;
    138 
    139    /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so
    140     * PR_GetLibraryFilePathname works with either the base library name or a
    141     * function pointer, depending on the platform.
    142     * We require the address of a function in the "reference library",
    143     * provided by the caller. To avoid getting the address of the stub/thunk
    144     * of an exported function by accident, use the address of a static
    145     * function rather than an exported function.
    146     */
    147    fullPath = PR_GetLibraryFilePathname(existingShLibName,
    148                                         staticShLibFunc);
    149 
    150    if (fullPath) {
    151        lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
    152 #ifdef XP_UNIX
    153        if (!lib) {
    154            /*
    155             * If fullPath is a symbolic link, resolve the symbolic
    156             * link and try again.
    157             */
    158            char* originalfullPath = loader_GetOriginalPathname(fullPath);
    159            if (originalfullPath) {
    160                PR_Free(fullPath);
    161                fullPath = originalfullPath;
    162                lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
    163            }
    164        }
    165 #endif
    166        PR_Free(fullPath);
    167    }
    168    if (!lib) {
    169 #ifdef DEBUG_LOADER
    170        PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName);
    171 #endif
    172        libSpec.type = PR_LibSpec_Pathname;
    173        libSpec.value.pathname = newShLibName;
    174        lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
    175    }
    176    if (NULL == lib) {
    177 #ifdef DEBUG_LOADER
    178        PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName);
    179 #endif
    180    }
    181    return lib;
    182 }