When a dynamic NSS module is built and linked against a thread
library, it may pull in that thread library at run time. If the process started out single-threaded, this could cause attempts to release locks that do not exist. Guard against this possibility by checking __isthreaded before invoking thread primitives. A similar problem remains if the process is linked against one thread library, but the NSS module is linked against another. This can only be avoided by careful design of the NSS module. Submitted by: Sean McNeil <sean@mcneil.com> (mostly; bugs are mine)
This commit is contained in:
parent
824ee6270f
commit
3c19db1378
@ -75,6 +75,6 @@ name##_getstate(struct name##_state **p) \
|
||||
return (rv); \
|
||||
} \
|
||||
/* allow the macro invocation to end with a semicolon */ \
|
||||
typedef int _##name##_bmVjdGFy
|
||||
struct _clashproof_bmVjdGFy
|
||||
|
||||
#endif /* _NSS_TLS_H_ */
|
||||
|
@ -316,9 +316,11 @@ nss_configure(void)
|
||||
static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static time_t confmod;
|
||||
struct stat statbuf;
|
||||
int result;
|
||||
int result, isthreaded;
|
||||
const char *path;
|
||||
|
||||
result = 0;
|
||||
isthreaded = __isthreaded;
|
||||
#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT)
|
||||
/* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built
|
||||
* for debugging purposes and MUST NEVER be used in production.
|
||||
@ -331,16 +333,20 @@ nss_configure(void)
|
||||
return (0);
|
||||
if (statbuf.st_mtime <= confmod)
|
||||
return (0);
|
||||
result = _pthread_mutex_trylock(&conf_lock);
|
||||
if (result != 0)
|
||||
return (0);
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
result = _pthread_rwlock_wrlock(&nss_lock);
|
||||
if (result != 0)
|
||||
goto fin2;
|
||||
if (isthreaded) {
|
||||
result = _pthread_mutex_trylock(&conf_lock);
|
||||
if (result != 0)
|
||||
return (0);
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
result = _pthread_rwlock_wrlock(&nss_lock);
|
||||
if (result != 0)
|
||||
goto fin2;
|
||||
}
|
||||
_nsyyin = fopen(path, "r");
|
||||
if (_nsyyin == NULL)
|
||||
if (_nsyyin == NULL) {
|
||||
result = errno;
|
||||
goto fin;
|
||||
}
|
||||
VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
|
||||
(vector_free_elem)ns_dbt_free);
|
||||
VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
|
||||
@ -353,10 +359,14 @@ nss_configure(void)
|
||||
(void)atexit(nss_atexit);
|
||||
confmod = statbuf.st_mtime;
|
||||
fin:
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
result = _pthread_rwlock_rdlock(&nss_lock);
|
||||
if (isthreaded) {
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
if (result == 0)
|
||||
result = _pthread_rwlock_rdlock(&nss_lock);
|
||||
}
|
||||
fin2:
|
||||
(void)_pthread_mutex_unlock(&conf_lock);
|
||||
if (isthreaded)
|
||||
(void)_pthread_mutex_unlock(&conf_lock);
|
||||
return (result);
|
||||
}
|
||||
|
||||
@ -510,12 +520,17 @@ ns_mod_free(ns_mod *mod)
|
||||
static void
|
||||
nss_atexit(void)
|
||||
{
|
||||
(void)_pthread_rwlock_wrlock(&nss_lock);
|
||||
int isthreaded;
|
||||
|
||||
isthreaded = __isthreaded;
|
||||
if (isthreaded)
|
||||
(void)_pthread_rwlock_wrlock(&nss_lock);
|
||||
VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
|
||||
(vector_free_elem)ns_dbt_free);
|
||||
VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
|
||||
(vector_free_elem)ns_mod_free);
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
if (isthreaded)
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -568,13 +583,16 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
|
||||
const ns_src *srclist;
|
||||
nss_method method;
|
||||
void *mdata;
|
||||
int serrno, i, result, srclistsize;
|
||||
int isthreaded, serrno, i, result, srclistsize;
|
||||
|
||||
isthreaded = __isthreaded;
|
||||
serrno = errno;
|
||||
result = _pthread_rwlock_rdlock(&nss_lock);
|
||||
if (result != 0) {
|
||||
result = NS_UNAVAIL;
|
||||
goto fin;
|
||||
if (isthreaded) {
|
||||
result = _pthread_rwlock_rdlock(&nss_lock);
|
||||
if (result != 0) {
|
||||
result = NS_UNAVAIL;
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
result = nss_configure();
|
||||
if (result != 0) {
|
||||
@ -604,7 +622,8 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
if (isthreaded)
|
||||
(void)_pthread_rwlock_unlock(&nss_lock);
|
||||
fin:
|
||||
errno = serrno;
|
||||
return (result);
|
||||
|
@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
#include "un-namespace.h"
|
||||
#include "libc_private.h"
|
||||
|
||||
|
||||
struct group;
|
||||
@ -60,7 +61,7 @@ static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT
|
||||
|
||||
#define SET_TERMINATOR(x, y) \
|
||||
do { \
|
||||
if (_pthread_main_np()) \
|
||||
if (!__isthreaded || _pthread_main_np()) \
|
||||
_term_main_##x = (y); \
|
||||
else { \
|
||||
(void)_pthread_once(&_term_once_##x, _term_create_##x); \
|
||||
@ -69,7 +70,7 @@ do { \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_TERMINATOR(x) \
|
||||
(_pthread_main_np() ? \
|
||||
(!__isthreaded || _pthread_main_np() ? \
|
||||
(_term_main_##x) : \
|
||||
((void)_pthread_once(&_term_once_##x, _term_create_##x), \
|
||||
_pthread_getspecific(_term_key_##x)))
|
||||
|
Loading…
Reference in New Issue
Block a user