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