Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 /*
6 * Allow freebl and softoken to be loaded without util or NSPR.
7 *
8 * These symbols are overridden once real NSPR, and libutil are attached.
9 */
10 #define _GNU_SOURCE 1
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <fcntl.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include <sys/time.h>
18 #include <dlfcn.h>
19 #include <prio.h>
20 #include <prlink.h>
21 #include <prlog.h>
22 #include <prthread.h>
23 #include <plstr.h>
24 #include <prinit.h>
25 #include <prlock.h>
26 #include <prmem.h>
27 #include <prerror.h>
28 #include <prmon.h>
29 #include <pratom.h>
30 #include <prsystem.h>
31 #include <prinrval.h>
32 #include <prtime.h>
33 #include <prcvar.h>
34 #include <secasn1.h>
35 #include <secdig.h>
36 #include <secport.h>
37 #include <secitem.h>
38 #include <blapi.h>
39 #include <private/pprio.h>
41 #define FREEBL_NO_WEAK 1
43 #define WEAK __attribute__((weak))
45 #ifdef FREEBL_NO_WEAK
47 /*
48 * This uses function pointers.
49 *
50 * CONS: A separate function is needed to
51 * fill in the function pointers.
52 *
53 * PROS: it works on all platforms.
54 * it allows for dynamically finding nspr and libutil, even once
55 * softoken is loaded and running. (NOTE: this may be a problem if
56 * we switch between the stubs and real NSPR on the fly. NSPR will
57 * do bad things if passed an _FakeArena to free or allocate from).
58 */
59 #define STUB_DECLARE(ret, fn, args) \
60 typedef ret (*type_##fn) args; \
61 static type_##fn ptr_##fn = NULL
63 #define STUB_SAFE_CALL0(fn) \
64 if (ptr_##fn) { return ptr_##fn(); }
65 #define STUB_SAFE_CALL1(fn,a1) \
66 if (ptr_##fn) { return ptr_##fn(a1); }
67 #define STUB_SAFE_CALL2(fn,a1,a2) \
68 if (ptr_##fn) { return ptr_##fn(a1,a2); }
69 #define STUB_SAFE_CALL3(fn,a1,a2,a3) \
70 if (ptr_##fn) { return ptr_##fn(a1,a2,a3); }
71 #define STUB_SAFE_CALL4(fn,a1,a2,a3,a4) \
72 if (ptr_##fn) { return ptr_##fn(a1,a2,a3,a4); }
73 #define STUB_SAFE_CALL6(fn,a1,a2,a3,a4,a5,a6) \
74 if (ptr_##fn) { return ptr_##fn(a1,a2,a3,a4,a5,a6); }
76 #define STUB_FETCH_FUNCTION(fn) \
77 ptr_##fn = (type_##fn) dlsym(lib,#fn); \
78 if (ptr_##fn == NULL) { \
79 return SECFailure; \
80 }
82 #else
83 /*
84 * this uses the loader weak attribute. it works automatically, but once
85 * freebl is loaded, the symbols are 'fixed' (later loading of NSPR or
86 * libutil will not resolve these symbols.
87 */
89 #define STUB_DECLARE(ret, fn, args) \
90 WEAK extern ret fn args
92 #define STUB_SAFE_CALL0(fn) \
93 if (fn) { return fn(); }
94 #define STUB_SAFE_CALL1(fn,a1) \
95 if (fn) { return fn(a1); }
96 #define STUB_SAFE_CALL2(fn,a1,a2) \
97 if (fn) { return fn(a1,a2); }
98 #define STUB_SAFE_CALL3(fn,a1,a2,a3) \
99 if (fn) { return fn(a1,a2,a3); }
100 #define STUB_SAFE_CALL4(fn,a1,a2,a3,a4) \
101 if (fn) { return fn(a1,a2,a3,a4); }
102 #define STUB_SAFE_CALL6(fn,a1,a2,a3,a4,a5,a6) \
103 if (fn) { return fn(a1,a2,a3,a4,a5,a6); }
104 #endif
107 STUB_DECLARE(void *,PORT_Alloc_Util,(size_t len));
108 STUB_DECLARE(void *,PORT_ArenaAlloc_Util,(PLArenaPool *arena, size_t size));
109 STUB_DECLARE(void *,PORT_ArenaZAlloc_Util,(PLArenaPool *arena, size_t size));
110 STUB_DECLARE(void ,PORT_Free_Util,(void *ptr));
111 STUB_DECLARE(void ,PORT_FreeArena_Util,(PLArenaPool *arena, PRBool zero));
112 STUB_DECLARE(int,PORT_GetError_Util,(void));
113 STUB_DECLARE(PLArenaPool *,PORT_NewArena_Util,(unsigned long chunksize));
114 STUB_DECLARE(void,PORT_SetError_Util,(int value));
115 STUB_DECLARE(void *,PORT_ZAlloc_Util,(size_t len));
116 STUB_DECLARE(void,PORT_ZFree_Util,(void *ptr, size_t len));
118 STUB_DECLARE(void,PR_Assert,(const char *s, const char *file, PRIntn ln));
119 STUB_DECLARE(PRStatus,PR_CallOnce,(PRCallOnceType *once, PRCallOnceFN func));
120 STUB_DECLARE(PRStatus,PR_Close,(PRFileDesc *fd));
121 STUB_DECLARE(void,PR_DestroyLock,(PRLock *lock));
122 STUB_DECLARE(void,PR_DestroyCondVar,(PRCondVar *cvar));
123 STUB_DECLARE(void,PR_Free,(void *ptr));
124 STUB_DECLARE(char * ,PR_GetLibraryFilePathname,(const char *name,
125 PRFuncPtr addr));
126 STUB_DECLARE(PRFileDesc *,PR_ImportPipe,(PROsfd osfd));
127 STUB_DECLARE(void,PR_Lock,(PRLock *lock));
128 STUB_DECLARE(PRCondVar *,PR_NewCondVar,(PRLock *lock));
129 STUB_DECLARE(PRLock *,PR_NewLock,(void));
130 STUB_DECLARE(PRStatus,PR_NotifyCondVar,(PRCondVar *cvar));
131 STUB_DECLARE(PRStatus,PR_NotifyAllCondVar,(PRCondVar *cvar));
132 STUB_DECLARE(PRFileDesc *,PR_Open,(const char *name, PRIntn flags,
133 PRIntn mode));
134 STUB_DECLARE(PRInt32,PR_Read,(PRFileDesc *fd, void *buf, PRInt32 amount));
135 STUB_DECLARE(PROffset32,PR_Seek,(PRFileDesc *fd, PROffset32 offset,
136 PRSeekWhence whence));
137 STUB_DECLARE(PRStatus,PR_Sleep,(PRIntervalTime ticks));
138 STUB_DECLARE(PRStatus,PR_Unlock,(PRLock *lock));
139 STUB_DECLARE(PRStatus,PR_WaitCondVar,(PRCondVar *cvar,
140 PRIntervalTime timeout));
143 STUB_DECLARE(SECItem *,SECITEM_AllocItem_Util,(PLArenaPool *arena,
144 SECItem *item,unsigned int len));
145 STUB_DECLARE(SECComparison,SECITEM_CompareItem_Util,(const SECItem *a,
146 const SECItem *b));
147 STUB_DECLARE(SECStatus,SECITEM_CopyItem_Util,(PLArenaPool *arena,
148 SECItem *to,const SECItem *from));
149 STUB_DECLARE(void,SECITEM_FreeItem_Util,(SECItem *zap, PRBool freeit));
150 STUB_DECLARE(void,SECITEM_ZfreeItem_Util,(SECItem *zap, PRBool freeit));
151 STUB_DECLARE(SECOidTag,SECOID_FindOIDTag_Util,(const SECItem *oid));
152 STUB_DECLARE(int, NSS_SecureMemcmp,(const void *a, const void *b, size_t n));
155 #define PORT_ZNew_stub(type) (type*)PORT_ZAlloc_stub(sizeof(type))
156 #define PORT_New_stub(type) (type*)PORT_Alloc_stub(sizeof(type))
157 #define PORT_ZNewArray_stub(type, num) \
158 (type*) PORT_ZAlloc_stub (sizeof(type)*(num))
161 /*
162 * NOTE: in order to support hashing only the memory allocation stubs,
163 * the get library name stubs, and the file io stubs are needed (the latter
164 * two are for the library verification). The remaining stubs are simply to
165 * compile. Attempts to use the library for other operations without NSPR
166 * will most likely fail.
167 */
170 /* memory */
171 extern void *
172 PORT_Alloc_stub(size_t len)
173 {
174 STUB_SAFE_CALL1(PORT_Alloc_Util, len);
175 return malloc(len);
176 }
178 extern void
179 PORT_Free_stub(void *ptr)
180 {
181 STUB_SAFE_CALL1(PORT_Free_Util, ptr);
182 return free(ptr);
183 }
185 extern void *
186 PORT_ZAlloc_stub(size_t len)
187 {
188 STUB_SAFE_CALL1(PORT_ZAlloc_Util, len);
189 void *ptr = malloc(len);
190 if (ptr) {
191 memset(ptr, 0, len);
192 }
193 return ptr;
194 }
197 extern void
198 PORT_ZFree_stub(void *ptr, size_t len)
199 {
200 STUB_SAFE_CALL2(PORT_ZFree_Util, ptr, len);
201 memset(ptr, 0, len);
202 return free(ptr);
203 }
205 extern void
206 PR_Free_stub(void *ptr)
207 {
208 STUB_SAFE_CALL1(PR_Free, ptr);
209 return free(ptr);
210 }
212 /*
213 * arenas
214 *
215 */
216 extern PLArenaPool *
217 PORT_NewArena_stub(unsigned long chunksize)
218 {
219 STUB_SAFE_CALL1(PORT_NewArena_Util, chunksize);
220 abort();
221 return NULL;
222 }
224 extern void *
225 PORT_ArenaAlloc_stub(PLArenaPool *arena, size_t size)
226 {
228 STUB_SAFE_CALL2(PORT_ArenaZAlloc_Util, arena, size);
229 abort();
230 return NULL;
231 }
233 extern void *
234 PORT_ArenaZAlloc_stub(PLArenaPool *arena, size_t size)
235 {
237 STUB_SAFE_CALL2(PORT_ArenaZAlloc_Util, arena, size);
238 abort();
239 return NULL;
240 }
242 extern void
243 PORT_FreeArena_stub(PLArenaPool *arena, PRBool zero)
244 {
246 STUB_SAFE_CALL2(PORT_FreeArena_Util, arena, zero);
247 abort();
248 }
251 /* io */
252 extern PRFileDesc *
253 PR_Open_stub(const char *name, PRIntn flags, PRIntn mode)
254 {
255 int *lfd = NULL;
256 int fd;
257 int lflags = 0;
259 STUB_SAFE_CALL3(PR_Open, name, flags, mode);
261 if (flags & PR_RDWR) {
262 lflags = O_RDWR;
263 } else if (flags & PR_WRONLY) {
264 lflags = O_WRONLY;
265 } else {
266 lflags = O_RDONLY;
267 }
269 if (flags & PR_EXCL)
270 lflags |= O_EXCL;
271 if (flags & PR_APPEND)
272 lflags |= O_APPEND;
273 if (flags & PR_TRUNCATE)
274 lflags |= O_TRUNC;
276 fd = open(name, lflags, mode);
277 if (fd >= 0) {
278 lfd = PORT_New_stub(int);
279 if (lfd != NULL) {
280 *lfd = fd;
281 }
282 }
283 return (PRFileDesc *)lfd;
284 }
286 extern PRFileDesc *
287 PR_ImportPipe_stub(PROsfd fd)
288 {
289 int *lfd = NULL;
291 STUB_SAFE_CALL1(PR_ImportPipe, fd);
293 lfd = PORT_New_stub(int);
294 if (lfd != NULL) {
295 *lfd = fd;
296 }
297 return (PRFileDesc *)lfd;
298 }
300 extern PRStatus
301 PR_Close_stub(PRFileDesc *fd)
302 {
303 int *lfd;
304 STUB_SAFE_CALL1(PR_Close, fd);
306 lfd = (int *)fd;
307 close(*lfd);
308 PORT_Free_stub(lfd);
310 return PR_SUCCESS;
311 }
313 extern PRInt32
314 PR_Read_stub(PRFileDesc *fd, void *buf, PRInt32 amount)
315 {
316 int *lfd;
317 STUB_SAFE_CALL3(PR_Read, fd, buf, amount);
319 lfd = (int *)fd;
320 return read(*lfd, buf, amount);
321 }
323 extern PROffset32
324 PR_Seek_stub(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
325 {
326 int *lfd;
327 int lwhence = SEEK_SET;;
328 STUB_SAFE_CALL3(PR_Seek, fd, offset, whence);
329 lfd = (int *)fd;
330 switch (whence) {
331 case PR_SEEK_CUR:
332 lwhence = SEEK_CUR;
333 break;
334 case PR_SEEK_END:
335 lwhence = SEEK_END;
336 break;
337 }
339 return lseek(*lfd, offset, lwhence);
340 }
343 /*
344 * library
345 */
346 extern char *
347 PR_GetLibraryFilePathname_stub(const char *name, PRFuncPtr addr)
348 {
349 Dl_info dli;
350 char *result;
352 STUB_SAFE_CALL2(PR_GetLibraryFilePathname, name, addr);
354 if (dladdr((void *)addr, &dli) == 0) {
355 return NULL;
356 }
357 result = PORT_Alloc_stub(strlen(dli.dli_fname)+1);
358 if (result != NULL) {
359 strcpy(result, dli.dli_fname);
360 }
361 return result;
362 }
365 #include <errno.h>
367 /* errors */
368 extern int
369 PORT_GetError_stub(void)
370 {
371 STUB_SAFE_CALL0(PORT_GetError_Util);
372 return errno;
373 }
375 extern void
376 PORT_SetError_stub(int value)
377 {
378 STUB_SAFE_CALL1(PORT_SetError_Util, value);
379 errno = value;
380 }
382 /* misc */
383 extern void
384 PR_Assert_stub(const char *s, const char *file, PRIntn ln)
385 {
386 STUB_SAFE_CALL3(PR_Assert, s, file, ln);
387 fprintf(stderr, "%s line %d: %s\n", file, ln, s);
388 abort();
389 }
391 /* time */
392 extern PRStatus
393 PR_Sleep_stub(PRIntervalTime ticks)
394 {
395 STUB_SAFE_CALL1(PR_Sleep, ticks);
396 usleep(ticks*1000);
397 return PR_SUCCESS;
398 }
401 /* locking */
402 extern PRLock *
403 PR_NewLock_stub(void)
404 {
405 STUB_SAFE_CALL0(PR_NewLock);
406 abort();
407 return NULL;
408 }
410 extern PRStatus
411 PR_Unlock_stub(PRLock *lock)
412 {
413 STUB_SAFE_CALL1(PR_Unlock, lock);
414 abort();
415 return PR_FAILURE;
416 }
418 extern void
419 PR_Lock_stub(PRLock *lock)
420 {
421 STUB_SAFE_CALL1(PR_Lock, lock);
422 abort();
423 return;
424 }
426 extern void
427 PR_DestroyLock_stub(PRLock *lock)
428 {
429 STUB_SAFE_CALL1(PR_DestroyLock, lock);
430 abort();
431 return;
432 }
434 extern PRCondVar *
435 PR_NewCondVar_stub(PRLock *lock)
436 {
437 STUB_SAFE_CALL1(PR_NewCondVar, lock);
438 abort();
439 return NULL;
440 }
442 extern PRStatus
443 PR_NotifyCondVar_stub(PRCondVar *cvar)
444 {
445 STUB_SAFE_CALL1(PR_NotifyCondVar, cvar);
446 abort();
447 return PR_FAILURE;
448 }
450 extern PRStatus
451 PR_NotifyAllCondVar_stub(PRCondVar *cvar)
452 {
453 STUB_SAFE_CALL1(PR_NotifyAllCondVar, cvar);
454 abort();
455 return PR_FAILURE;
456 }
458 extern PRStatus
459 PR_WaitCondVar_stub(PRCondVar *cvar, PRIntervalTime timeout)
460 {
461 STUB_SAFE_CALL2(PR_WaitCondVar, cvar, timeout);
462 abort();
463 return PR_FAILURE;
464 }
468 extern void
469 PR_DestroyCondVar_stub(PRCondVar *cvar)
470 {
471 STUB_SAFE_CALL1(PR_DestroyCondVar, cvar);
472 abort();
473 return;
474 }
476 /*
477 * NOTE: this presupposes GCC 4.1
478 */
479 extern PRStatus
480 PR_CallOnce_stub(PRCallOnceType *once, PRCallOnceFN func)
481 {
482 STUB_SAFE_CALL2(PR_CallOnce, once, func);
483 abort();
484 return PR_FAILURE;
485 }
488 /*
489 * SECITEMS implement Item Utilities
490 */
491 extern void
492 SECITEM_FreeItem_stub(SECItem *zap, PRBool freeit)
493 {
494 STUB_SAFE_CALL2(SECITEM_FreeItem_Util, zap, freeit);
495 abort();
496 }
498 extern SECItem *
499 SECITEM_AllocItem_stub(PLArenaPool *arena, SECItem *item, unsigned int len)
500 {
501 STUB_SAFE_CALL3(SECITEM_AllocItem_Util, arena, item, len);
502 abort();
503 return NULL;
504 }
506 extern SECComparison
507 SECITEM_CompareItem_stub(const SECItem *a, const SECItem *b)
508 {
509 STUB_SAFE_CALL2(SECITEM_CompareItem_Util, a, b);
510 abort();
511 return SECEqual;
512 }
514 extern SECStatus
515 SECITEM_CopyItem_stub(PLArenaPool *arena, SECItem *to, const SECItem *from)
516 {
517 STUB_SAFE_CALL3(SECITEM_CopyItem_Util, arena, to, from);
518 abort();
519 return SECFailure;
520 }
522 extern SECOidTag
523 SECOID_FindOIDTag_stub(const SECItem *oid)
524 {
525 STUB_SAFE_CALL1(SECOID_FindOIDTag_Util, oid);
526 abort();
527 return SEC_OID_UNKNOWN;
528 }
530 extern void
531 SECITEM_ZfreeItem_stub(SECItem *zap, PRBool freeit)
532 {
533 STUB_SAFE_CALL2(SECITEM_ZfreeItem_Util, zap, freeit);
534 abort();
535 }
537 extern int
538 NSS_SecureMemcmp_stub(const void *a, const void *b, size_t n)
539 {
540 STUB_SAFE_CALL3(NSS_SecureMemcmp, a, b, n);
541 abort();
542 }
544 #ifdef FREEBL_NO_WEAK
546 static const char *nsprLibName = SHLIB_PREFIX"nspr4."SHLIB_SUFFIX;
547 static const char *nssutilLibName = SHLIB_PREFIX"nssutil3."SHLIB_SUFFIX;
549 static SECStatus
550 freebl_InitNSPR(void *lib)
551 {
552 STUB_FETCH_FUNCTION(PR_Free);
553 STUB_FETCH_FUNCTION(PR_Open);
554 STUB_FETCH_FUNCTION(PR_ImportPipe);
555 STUB_FETCH_FUNCTION(PR_Close);
556 STUB_FETCH_FUNCTION(PR_Read);
557 STUB_FETCH_FUNCTION(PR_Seek);
558 STUB_FETCH_FUNCTION(PR_GetLibraryFilePathname);
559 STUB_FETCH_FUNCTION(PR_Assert);
560 STUB_FETCH_FUNCTION(PR_Sleep);
561 STUB_FETCH_FUNCTION(PR_CallOnce);
562 STUB_FETCH_FUNCTION(PR_NewCondVar);
563 STUB_FETCH_FUNCTION(PR_NotifyCondVar);
564 STUB_FETCH_FUNCTION(PR_NotifyAllCondVar);
565 STUB_FETCH_FUNCTION(PR_WaitCondVar);
566 STUB_FETCH_FUNCTION(PR_DestroyCondVar);
567 STUB_FETCH_FUNCTION(PR_NewLock);
568 STUB_FETCH_FUNCTION(PR_Unlock);
569 STUB_FETCH_FUNCTION(PR_Lock);
570 STUB_FETCH_FUNCTION(PR_DestroyLock);
571 return SECSuccess;
572 }
574 static SECStatus
575 freebl_InitNSSUtil(void *lib)
576 {
577 STUB_FETCH_FUNCTION(PORT_Alloc_Util);
578 STUB_FETCH_FUNCTION(PORT_Free_Util);
579 STUB_FETCH_FUNCTION(PORT_ZAlloc_Util);
580 STUB_FETCH_FUNCTION(PORT_ZFree_Util);
581 STUB_FETCH_FUNCTION(PORT_NewArena_Util);
582 STUB_FETCH_FUNCTION(PORT_ArenaAlloc_Util);
583 STUB_FETCH_FUNCTION(PORT_ArenaZAlloc_Util);
584 STUB_FETCH_FUNCTION(PORT_FreeArena_Util);
585 STUB_FETCH_FUNCTION(PORT_GetError_Util);
586 STUB_FETCH_FUNCTION(PORT_SetError_Util);
587 STUB_FETCH_FUNCTION(SECITEM_FreeItem_Util);
588 STUB_FETCH_FUNCTION(SECITEM_AllocItem_Util);
589 STUB_FETCH_FUNCTION(SECITEM_CompareItem_Util);
590 STUB_FETCH_FUNCTION(SECITEM_CopyItem_Util);
591 STUB_FETCH_FUNCTION(SECITEM_ZfreeItem_Util);
592 STUB_FETCH_FUNCTION(SECOID_FindOIDTag_Util);
593 STUB_FETCH_FUNCTION(NSS_SecureMemcmp);
594 return SECSuccess;
595 }
597 /*
598 * fetch the library if it's loaded. For NSS it should already be loaded
599 */
600 #define freebl_getLibrary(libName) \
601 dlopen (libName, RTLD_LAZY|RTLD_NOLOAD)
603 #define freebl_releaseLibrary(lib) \
604 if (lib) dlclose(lib)
606 static void * FREEBLnsprGlobalLib = NULL;
607 static void * FREEBLnssutilGlobalLib = NULL;
609 void __attribute ((destructor)) FREEBL_unload()
610 {
611 freebl_releaseLibrary(FREEBLnsprGlobalLib);
612 freebl_releaseLibrary(FREEBLnssutilGlobalLib);
613 }
614 #endif
616 /*
617 * load the symbols from the real libraries if available.
618 *
619 * if force is set, explicitly load the libraries if they are not already
620 * loaded. If we could not use the real libraries, return failure.
621 */
622 extern SECStatus
623 FREEBL_InitStubs()
624 {
625 SECStatus rv = SECSuccess;
626 #ifdef FREEBL_NO_WEAK
627 void *nspr = NULL;
628 void *nssutil = NULL;
630 /* NSPR should be first */
631 if (!FREEBLnsprGlobalLib) {
632 nspr = freebl_getLibrary(nsprLibName);
633 if (!nspr) {
634 return SECFailure;
635 }
636 rv = freebl_InitNSPR(nspr);
637 if (rv != SECSuccess) {
638 freebl_releaseLibrary(nspr);
639 return rv;
640 }
641 FREEBLnsprGlobalLib = nspr; /* adopt */
642 }
643 /* now load NSSUTIL */
644 if (!FREEBLnssutilGlobalLib) {
645 nssutil= freebl_getLibrary(nssutilLibName);
646 if (!nssutil) {
647 return SECFailure;
648 }
649 rv = freebl_InitNSSUtil(nssutil);
650 if (rv != SECSuccess) {
651 freebl_releaseLibrary(nssutil);
652 return rv;
653 }
654 FREEBLnssutilGlobalLib = nssutil; /* adopt */
655 }
656 #endif
658 return rv;
659 }