security/nss/lib/ssl/sslmutex.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 "seccomon.h"
     6 /* This ifdef should match the one in sslsnce.c */
     7 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
     9 #include "sslmutex.h"
    10 #include "prerr.h"
    12 static SECStatus single_process_sslMutex_Init(sslMutex* pMutex)
    13 {
    14     PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0 );
    16     pMutex->u.sslLock = PR_NewLock();
    17     if (!pMutex->u.sslLock) {
    18         return SECFailure;
    19     }
    20     return SECSuccess;
    21 }
    23 static SECStatus single_process_sslMutex_Destroy(sslMutex* pMutex)
    24 {
    25     PR_ASSERT(pMutex != 0);
    26     PR_ASSERT(pMutex->u.sslLock!= 0);
    27     if (!pMutex->u.sslLock) {
    28         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
    29         return SECFailure;
    30     }
    31     PR_DestroyLock(pMutex->u.sslLock);
    32     return SECSuccess;
    33 }
    35 static SECStatus single_process_sslMutex_Unlock(sslMutex* pMutex)
    36 {
    37     PR_ASSERT(pMutex != 0 );
    38     PR_ASSERT(pMutex->u.sslLock !=0);
    39     if (!pMutex->u.sslLock) {
    40         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
    41         return SECFailure;
    42     }
    43     PR_Unlock(pMutex->u.sslLock);
    44     return SECSuccess;
    45 }
    47 static SECStatus single_process_sslMutex_Lock(sslMutex* pMutex)
    48 {
    49     PR_ASSERT(pMutex != 0);
    50     PR_ASSERT(pMutex->u.sslLock != 0 );
    51     if (!pMutex->u.sslLock) {
    52         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
    53         return SECFailure;
    54     }
    55     PR_Lock(pMutex->u.sslLock);
    56     return SECSuccess;
    57 }
    59 #if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
    61 #include <unistd.h>
    62 #include <fcntl.h>
    63 #include <string.h>
    64 #include <errno.h>
    65 #include "unix_err.h"
    66 #include "pratom.h"
    68 #define SSL_MUTEX_MAGIC 0xfeedfd
    69 #define NONBLOCKING_POSTS 1	/* maybe this is faster */
    71 #if NONBLOCKING_POSTS
    73 #ifndef FNONBLOCK
    74 #define FNONBLOCK O_NONBLOCK
    75 #endif
    77 static int
    78 setNonBlocking(int fd, int nonBlocking)
    79 {
    80     int flags;
    81     int err;
    83     flags = fcntl(fd, F_GETFL, 0);
    84     if (0 > flags)
    85 	return flags;
    86     if (nonBlocking)
    87 	flags |= FNONBLOCK;
    88     else
    89 	flags &= ~FNONBLOCK;
    90     err = fcntl(fd, F_SETFL, flags);
    91     return err;
    92 }
    93 #endif
    95 SECStatus
    96 sslMutex_Init(sslMutex *pMutex, int shared)
    97 {
    98     int  err;
    99     PR_ASSERT(pMutex);
   100     pMutex->isMultiProcess = (PRBool)(shared != 0);
   101     if (!shared) {
   102         return single_process_sslMutex_Init(pMutex);
   103     }
   104     pMutex->u.pipeStr.mPipes[0] = -1;
   105     pMutex->u.pipeStr.mPipes[1] = -1;
   106     pMutex->u.pipeStr.mPipes[2] = -1;
   107     pMutex->u.pipeStr.nWaiters  =  0;
   109     err = pipe(pMutex->u.pipeStr.mPipes);
   110     if (err) {
   111 	nss_MD_unix_map_default_error(errno);
   112 	return err;
   113     }
   114 #if NONBLOCKING_POSTS
   115     err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1);
   116     if (err)
   117 	goto loser;
   118 #endif
   120     pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC;
   122 #if defined(LINUX) && defined(i386)
   123     /* Pipe starts out empty */
   124     return SECSuccess;
   125 #else
   126     /* Pipe starts with one byte. */
   127     return sslMutex_Unlock(pMutex);
   128 #endif
   130 loser:
   131     nss_MD_unix_map_default_error(errno);
   132     close(pMutex->u.pipeStr.mPipes[0]);
   133     close(pMutex->u.pipeStr.mPipes[1]);
   134     return SECFailure;
   135 }
   137 SECStatus
   138 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
   139 {
   140     if (PR_FALSE == pMutex->isMultiProcess) {
   141         return single_process_sslMutex_Destroy(pMutex);
   142     }
   143     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
   144 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   145 	return SECFailure;
   146     }
   147     close(pMutex->u.pipeStr.mPipes[0]);
   148     close(pMutex->u.pipeStr.mPipes[1]);
   150     if (processLocal) {
   151 	return SECSuccess;
   152     }
   154     pMutex->u.pipeStr.mPipes[0] = -1;
   155     pMutex->u.pipeStr.mPipes[1] = -1;
   156     pMutex->u.pipeStr.mPipes[2] = -1;
   157     pMutex->u.pipeStr.nWaiters  =  0;
   159     return SECSuccess;
   160 }
   162 #if defined(LINUX) && defined(i386)
   163 /* No memory barrier needed for this platform */
   165 /* nWaiters includes the holder of the lock (if any) and the number
   166 ** threads waiting for it.  After incrementing nWaiters, if the count
   167 ** is exactly 1, then you have the lock and may proceed.  If the 
   168 ** count is greater than 1, then you must wait on the pipe.
   169 */ 
   172 SECStatus 
   173 sslMutex_Unlock(sslMutex *pMutex)
   174 {
   175     PRInt32 newValue;
   176     if (PR_FALSE == pMutex->isMultiProcess) {
   177         return single_process_sslMutex_Unlock(pMutex);
   178     }
   180     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
   181 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   182 	return SECFailure;
   183     }
   184     /* Do Memory Barrier here. */
   185     newValue = PR_ATOMIC_DECREMENT(&pMutex->u.pipeStr.nWaiters);
   186     if (newValue > 0) {
   187 	int  cc;
   188 	char c  = 1;
   189 	do {
   190 	    cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
   191 	} while (cc < 0 && (errno == EINTR || errno == EAGAIN));
   192 	if (cc != 1) {
   193 	    if (cc < 0)
   194 		nss_MD_unix_map_default_error(errno);
   195 	    else
   196 		PORT_SetError(PR_UNKNOWN_ERROR);
   197 	    return SECFailure;
   198 	}
   199     }
   200     return SECSuccess;
   201 }
   203 SECStatus 
   204 sslMutex_Lock(sslMutex *pMutex)
   205 {
   206     PRInt32 newValue;
   207     if (PR_FALSE == pMutex->isMultiProcess) {
   208         return single_process_sslMutex_Lock(pMutex);
   209     }
   211     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
   212 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   213 	return SECFailure;
   214     }
   215     newValue = PR_ATOMIC_INCREMENT(&pMutex->u.pipeStr.nWaiters);
   216     /* Do Memory Barrier here. */
   217     if (newValue > 1) {
   218 	int   cc;
   219 	char  c;
   220 	do {
   221 	    cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
   222 	} while (cc < 0 && errno == EINTR);
   223 	if (cc != 1) {
   224 	    if (cc < 0)
   225 		nss_MD_unix_map_default_error(errno);
   226 	    else
   227 		PORT_SetError(PR_UNKNOWN_ERROR);
   228 	    return SECFailure;
   229 	}
   230     }
   231     return SECSuccess;
   232 }
   234 #else
   236 /* Using Atomic operations requires the use of a memory barrier instruction 
   237 ** on PowerPC, Sparc, and Alpha.  NSPR's PR_Atomic functions do not perform
   238 ** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
   239 ** So, we don't use them on those platforms. 
   240 */
   242 SECStatus 
   243 sslMutex_Unlock(sslMutex *pMutex)
   244 {
   245     int  cc;
   246     char c  = 1;
   248     if (PR_FALSE == pMutex->isMultiProcess) {
   249         return single_process_sslMutex_Unlock(pMutex);
   250     }
   252     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
   253 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   254 	return SECFailure;
   255     }
   256     do {
   257 	cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
   258     } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
   259     if (cc != 1) {
   260 	if (cc < 0)
   261 	    nss_MD_unix_map_default_error(errno);
   262 	else
   263 	    PORT_SetError(PR_UNKNOWN_ERROR);
   264 	return SECFailure;
   265     }
   267     return SECSuccess;
   268 }
   270 SECStatus 
   271 sslMutex_Lock(sslMutex *pMutex)
   272 {
   273     int   cc;
   274     char  c;
   276     if (PR_FALSE == pMutex->isMultiProcess) {
   277         return single_process_sslMutex_Lock(pMutex);
   278     }
   280     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
   281 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   282 	return SECFailure;
   283     }
   285     do {
   286 	cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
   287     } while (cc < 0 && errno == EINTR);
   288     if (cc != 1) {
   289 	if (cc < 0)
   290 	    nss_MD_unix_map_default_error(errno);
   291 	else
   292 	    PORT_SetError(PR_UNKNOWN_ERROR);
   293 	return SECFailure;
   294     }
   296     return SECSuccess;
   297 }
   299 #endif
   301 #elif defined(WIN32)
   303 #include "win32err.h"
   305 /* on Windows, we need to find the optimal type of locking mechanism to use
   306  for the sslMutex.
   308  There are 3 cases :
   309  1) single-process, use a PRLock, as for all other platforms
   310  2) Win95 multi-process, use a Win32 mutex
   311  3) on WINNT multi-process, use a PRLock + a Win32 mutex
   313 */
   315 #ifdef WINNT
   317 SECStatus sslMutex_2LevelInit(sslMutex *sem)
   318 {
   319     /*  the following adds a PRLock to sslMutex . This is done in each
   320         process of a multi-process server and is only needed on WINNT, if
   321         using fibers. We can't tell if native threads or fibers are used, so
   322         we always do it on WINNT
   323     */
   324     PR_ASSERT(sem);
   325     if (sem) {
   326         /* we need to reset the sslLock in the children or the single_process init
   327            function below will assert */
   328         sem->u.sslLock = NULL;
   329     }
   330     return single_process_sslMutex_Init(sem);
   331 }
   333 static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
   334 {
   335     return single_process_sslMutex_Destroy(sem);
   336 }
   338 #endif
   340 SECStatus
   341 sslMutex_Init(sslMutex *pMutex, int shared)
   342 {
   343 #ifdef WINNT
   344     SECStatus retvalue;
   345 #endif
   346     HANDLE hMutex;
   347     SECURITY_ATTRIBUTES attributes =
   348                                 { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
   350     PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 || 
   351               pMutex->u.sslMutx == INVALID_HANDLE_VALUE) );
   353     pMutex->isMultiProcess = (PRBool)(shared != 0);
   355     if (PR_FALSE == pMutex->isMultiProcess) {
   356         return single_process_sslMutex_Init(pMutex);
   357     }
   359 #ifdef WINNT
   360     /*  we need a lock on WINNT for fibers in the parent process */
   361     retvalue = sslMutex_2LevelInit(pMutex);
   362     if (SECSuccess != retvalue)
   363         return SECFailure;
   364 #endif
   366     if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 && 
   367         hMutex != INVALID_HANDLE_VALUE)) {
   368         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   369         return SECFailure;
   370     }
   371     attributes.bInheritHandle = (shared ? TRUE : FALSE);
   372     hMutex = CreateMutex(&attributes, FALSE, NULL);
   373     if (hMutex == NULL) {
   374         hMutex = INVALID_HANDLE_VALUE;
   375         nss_MD_win32_map_default_error(GetLastError());
   376         return SECFailure;
   377     }
   378     pMutex->u.sslMutx = hMutex;
   379     return SECSuccess;
   380 }
   382 SECStatus
   383 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
   384 {
   385     HANDLE hMutex;
   386     int    rv;
   387     int retvalue = SECSuccess;
   389     PR_ASSERT(pMutex != 0);
   390     if (PR_FALSE == pMutex->isMultiProcess) {
   391         return single_process_sslMutex_Destroy(pMutex);
   392     }
   394     /*  multi-process mode */    
   395 #ifdef WINNT
   396     /* on NT, get rid of the PRLock used for fibers within a process */
   397     retvalue = sslMutex_2LevelDestroy(pMutex);
   398 #endif
   400     PR_ASSERT( pMutex->u.sslMutx != 0 && 
   401                pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
   402     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 
   403         || hMutex == INVALID_HANDLE_VALUE) {
   404         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   405         return SECFailure;
   406     }
   408     rv = CloseHandle(hMutex); /* ignore error */
   409     if (!processLocal && rv) {
   410         pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
   411     }
   412     if (!rv) {
   413         nss_MD_win32_map_default_error(GetLastError());
   414         retvalue = SECFailure;
   415     }
   416     return retvalue;
   417 }
   419 int 
   420 sslMutex_Unlock(sslMutex *pMutex)
   421 {
   422     BOOL   success = FALSE;
   423     HANDLE hMutex;
   425     PR_ASSERT(pMutex != 0 );
   426     if (PR_FALSE == pMutex->isMultiProcess) {
   427         return single_process_sslMutex_Unlock(pMutex);
   428     }
   430     PR_ASSERT(pMutex->u.sslMutx != 0 && 
   431               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
   432     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
   433         hMutex == INVALID_HANDLE_VALUE) {
   434         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   435         return SECFailure;
   436     }
   437     success = ReleaseMutex(hMutex);
   438     if (!success) {
   439         nss_MD_win32_map_default_error(GetLastError());
   440         return SECFailure;
   441     }
   442 #ifdef WINNT
   443     return single_process_sslMutex_Unlock(pMutex);
   444     /* release PRLock for other fibers in the process */
   445 #else
   446     return SECSuccess;
   447 #endif
   448 }
   450 int 
   451 sslMutex_Lock(sslMutex *pMutex)
   452 {
   453     HANDLE    hMutex;
   454     DWORD     event;
   455     DWORD     lastError;
   456     SECStatus rv;
   457     SECStatus retvalue = SECSuccess;
   458     PR_ASSERT(pMutex != 0);
   460     if (PR_FALSE == pMutex->isMultiProcess) {
   461         return single_process_sslMutex_Lock(pMutex);
   462     }
   463 #ifdef WINNT
   464     /* lock first to preserve from other threads/fibers
   465        in the same process */
   466     retvalue = single_process_sslMutex_Lock(pMutex);
   467 #endif
   468     PR_ASSERT(pMutex->u.sslMutx != 0 && 
   469               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
   470     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 || 
   471         hMutex == INVALID_HANDLE_VALUE) {
   472         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
   473         return SECFailure;      /* what else ? */
   474     }
   475     /* acquire the mutex to be the only owner accross all other processes */
   476     event = WaitForSingleObject(hMutex, INFINITE);
   477     switch (event) {
   478     case WAIT_OBJECT_0:
   479     case WAIT_ABANDONED:
   480         rv = SECSuccess;
   481         break;
   483     case WAIT_TIMEOUT:
   484 #if defined(WAIT_IO_COMPLETION)
   485     case WAIT_IO_COMPLETION:
   486 #endif
   487     default:            /* should never happen. nothing we can do. */
   488         PR_ASSERT(!("WaitForSingleObject returned invalid value."));
   489 	PORT_SetError(PR_UNKNOWN_ERROR);
   490 	rv = SECFailure;
   491 	break;
   493     case WAIT_FAILED:           /* failure returns this */
   494         rv = SECFailure;
   495         lastError = GetLastError();     /* for debugging */
   496         nss_MD_win32_map_default_error(lastError);
   497         break;
   498     }
   500     if (! (SECSuccess == retvalue && SECSuccess == rv)) {
   501         return SECFailure;
   502     }
   504     return SECSuccess;
   505 }
   507 #elif defined(XP_UNIX)
   509 #include <errno.h>
   510 #include "unix_err.h"
   512 SECStatus 
   513 sslMutex_Init(sslMutex *pMutex, int shared)
   514 {
   515     int rv;
   516     PR_ASSERT(pMutex);
   517     pMutex->isMultiProcess = (PRBool)(shared != 0);
   518     if (!shared) {
   519         return single_process_sslMutex_Init(pMutex);
   520     }
   521     do {
   522         rv = sem_init(&pMutex->u.sem, shared, 1);
   523     } while (rv < 0 && errno == EINTR);
   524     if (rv < 0) {
   525         nss_MD_unix_map_default_error(errno);
   526         return SECFailure;
   527     }
   528     return SECSuccess;
   529 }
   531 SECStatus 
   532 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
   533 {
   534     int rv;
   535     if (PR_FALSE == pMutex->isMultiProcess) {
   536         return single_process_sslMutex_Destroy(pMutex);
   537     }
   539     /* semaphores are global resources. See SEM_DESTROY(3) man page */
   540     if (processLocal) {
   541 	return SECSuccess;
   542     }
   543     do {
   544 	rv = sem_destroy(&pMutex->u.sem);
   545     } while (rv < 0 && errno == EINTR);
   546     if (rv < 0) {
   547 	nss_MD_unix_map_default_error(errno);
   548 	return SECFailure;
   549     }
   550     return SECSuccess;
   551 }
   553 SECStatus 
   554 sslMutex_Unlock(sslMutex *pMutex)
   555 {
   556     int rv;
   557     if (PR_FALSE == pMutex->isMultiProcess) {
   558         return single_process_sslMutex_Unlock(pMutex);
   559     }
   560     do {
   561 	rv = sem_post(&pMutex->u.sem);
   562     } while (rv < 0 && errno == EINTR);
   563     if (rv < 0) {
   564 	nss_MD_unix_map_default_error(errno);
   565 	return SECFailure;
   566     }
   567     return SECSuccess;
   568 }
   570 SECStatus 
   571 sslMutex_Lock(sslMutex *pMutex)
   572 {
   573     int rv;
   574     if (PR_FALSE == pMutex->isMultiProcess) {
   575         return single_process_sslMutex_Lock(pMutex);
   576     }
   577     do {
   578 	rv = sem_wait(&pMutex->u.sem);
   579     } while (rv < 0 && errno == EINTR);
   580     if (rv < 0) {
   581 	nss_MD_unix_map_default_error(errno);
   582 	return SECFailure;
   583     }
   584     return SECSuccess;
   585 }
   587 #else
   589 SECStatus 
   590 sslMutex_Init(sslMutex *pMutex, int shared)
   591 {
   592     PR_ASSERT(pMutex);
   593     pMutex->isMultiProcess = (PRBool)(shared != 0);
   594     if (!shared) {
   595         return single_process_sslMutex_Init(pMutex);
   596     }
   597     PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
   598     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
   599     return SECFailure;
   600 }
   602 SECStatus 
   603 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
   604 {
   605     PR_ASSERT(pMutex);
   606     if (PR_FALSE == pMutex->isMultiProcess) {
   607         return single_process_sslMutex_Destroy(pMutex);
   608     }
   609     PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
   610     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
   611     return SECFailure;
   612 }
   614 SECStatus 
   615 sslMutex_Unlock(sslMutex *pMutex)
   616 {
   617     PR_ASSERT(pMutex);
   618     if (PR_FALSE == pMutex->isMultiProcess) {
   619         return single_process_sslMutex_Unlock(pMutex);
   620     }
   621     PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
   622     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
   623     return SECFailure;
   624 }
   626 SECStatus 
   627 sslMutex_Lock(sslMutex *pMutex)
   628 {
   629     PR_ASSERT(pMutex);
   630     if (PR_FALSE == pMutex->isMultiProcess) {
   631         return single_process_sslMutex_Lock(pMutex);
   632     }
   633     PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
   634     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
   635     return SECFailure;
   636 }
   638 #endif
   640 #endif

mercurial