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:
Jacques Vidrine 2004-03-30 15:56:15 +00:00
parent d30d48a258
commit a03fd3b656
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=127625
3 changed files with 43 additions and 23 deletions

View file

@ -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_ */

View file

@ -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);

View file

@ -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)))