summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2010-03-10 13:23:25 +0000
committerjhb <jhb@FreeBSD.org>2010-03-10 13:23:25 +0000
commite0724fd324c89b8c46185fe402fd332141ea5bf5 (patch)
treedae7801acd654dfe736481930016ad68270d7757 /lib/libc
parent42dc39ae95f85b0f1bedbdfa406342f9ac3e4fcc (diff)
downloadFreeBSD-src-e0724fd324c89b8c46185fe402fd332141ea5bf5.zip
FreeBSD-src-e0724fd324c89b8c46185fe402fd332141ea5bf5.tar.gz
Use thr_once() with once_t controls to initialize various thread_key_t
objects used to provide per-thread storage in the RPC code. Almost all of these used double-checking with a dedicated mutex (tsd_lock) to do this before. However, that is not always safe with more relaxed memory orders. There were also other bugs, such as one in __rpc_createrr() that caused a new key to be allocated each time __rpc_createrr() was invoked. PR: threads/144558 Reported by: Sam Robb samrobb of averesystems com (key leak) MFC after: 1 week
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/rpc/Symbol.map4
-rw-r--r--lib/libc/rpc/clnt_simple.c22
-rw-r--r--lib/libc/rpc/getnetconfig.c29
-rw-r--r--lib/libc/rpc/key_call.c20
-rw-r--r--lib/libc/rpc/mt_misc.c27
-rw-r--r--lib/libc/rpc/mt_misc.h1
-rw-r--r--lib/libc/rpc/rpc_generic.c27
-rw-r--r--lib/libc/rpc/rpc_soc.c15
8 files changed, 81 insertions, 64 deletions
diff --git a/lib/libc/rpc/Symbol.map b/lib/libc/rpc/Symbol.map
index ccf0bfa..4f356de 100644
--- a/lib/libc/rpc/Symbol.map
+++ b/lib/libc/rpc/Symbol.map
@@ -239,10 +239,6 @@ FBSDprivate_1.0 {
__key_encryptsession_pk_LOCAL;
__key_decryptsession_pk_LOCAL;
__key_gendes_LOCAL;
- __tsd_lock; /*
- * Why does usr.bin/rpcinfo/Makefile need rpc_generic.c?
- * Remove this hack if rpcinfo stops building with it.
- */
__svc_clean_idle;
__rpc_gss_unwrap;
__rpc_gss_unwrap_stub;
diff --git a/lib/libc/rpc/clnt_simple.c b/lib/libc/rpc/clnt_simple.c
index 12b6679..ba21d2d 100644
--- a/lib/libc/rpc/clnt_simple.c
+++ b/lib/libc/rpc/clnt_simple.c
@@ -76,7 +76,11 @@ struct rpc_call_private {
char nettype[NETIDLEN]; /* Network type */
};
static struct rpc_call_private *rpc_call_private_main;
+static thread_key_t rpc_call_key;
+static once_t rpc_call_once = ONCE_INITIALIZER;
+static int rpc_call_key_error;
+static void rpc_call_key_init(void);
static void rpc_call_destroy(void *);
static void
@@ -91,6 +95,13 @@ rpc_call_destroy(void *vp)
}
}
+static void
+rpc_call_key_init(void)
+{
+
+ rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
+}
+
/*
* This is the simplified interface to the client rpc layer.
* The client handle is not destroyed here and is reused for
@@ -112,17 +123,16 @@ rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
enum clnt_stat clnt_stat;
struct timeval timeout, tottimeout;
- static thread_key_t rpc_call_key;
int main_thread = 1;
if ((main_thread = thr_main())) {
rcp = rpc_call_private_main;
} else {
- if (rpc_call_key == 0) {
- mutex_lock(&tsd_lock);
- if (rpc_call_key == 0)
- thr_keycreate(&rpc_call_key, rpc_call_destroy);
- mutex_unlock(&tsd_lock);
+ if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
+ rpc_call_key_error != 0) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = rpc_call_key_error;
+ return (rpc_createerr.cf_stat);
}
rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
}
diff --git a/lib/libc/rpc/getnetconfig.c b/lib/libc/rpc/getnetconfig.c
index e5db51a..1310e36 100644
--- a/lib/libc/rpc/getnetconfig.c
+++ b/lib/libc/rpc/getnetconfig.c
@@ -130,21 +130,29 @@ static struct netconfig *dup_ncp(struct netconfig *);
static FILE *nc_file; /* for netconfig db */
-static pthread_mutex_t nc_file_lock = PTHREAD_MUTEX_INITIALIZER;
+static mutex_t nc_file_lock = MUTEX_INITIALIZER;
static struct netconfig_info ni = { 0, 0, NULL, NULL};
-static pthread_mutex_t ni_lock = PTHREAD_MUTEX_INITIALIZER;
+static mutex_t ni_lock = MUTEX_INITIALIZER;
+static thread_key_t nc_key;
+static once_t nc_once = ONCE_INITIALIZER;
+static int nc_key_error;
+
+static void
+nc_key_init(void)
+{
+
+ nc_key_error = thr_keycreate(&nc_key, free);
+}
#define MAXNETCONFIGLINE 1000
static int *
__nc_error()
{
- static pthread_mutex_t nc_lock = PTHREAD_MUTEX_INITIALIZER;
- static thread_key_t nc_key = 0;
static int nc_error = 0;
- int error, *nc_addr;
+ int *nc_addr;
/*
* Use the static `nc_error' if we are the main thread
@@ -153,15 +161,8 @@ __nc_error()
*/
if (thr_main())
return (&nc_error);
- if (nc_key == 0) {
- error = 0;
- mutex_lock(&nc_lock);
- if (nc_key == 0)
- error = thr_keycreate(&nc_key, free);
- mutex_unlock(&nc_lock);
- if (error)
- return (&nc_error);
- }
+ if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0)
+ return (&nc_error);
if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) {
nc_addr = (int *)malloc(sizeof (int));
if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
diff --git a/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c
index 6cc1139..afb11c8 100644
--- a/lib/libc/rpc/key_call.c
+++ b/lib/libc/rpc/key_call.c
@@ -279,6 +279,9 @@ struct key_call_private {
uid_t uid; /* user-id at last authorization */
};
static struct key_call_private *key_call_private_main = NULL;
+static thread_key_t key_call_key;
+static once_t key_call_once = ONCE_INITIALIZER;
+static int key_call_key_error;
static void
key_call_destroy(void *vp)
@@ -292,6 +295,13 @@ key_call_destroy(void *vp)
}
}
+static void
+key_call_init(void)
+{
+
+ key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
+}
+
/*
* Keep the handle cached. This call may be made quite often.
*/
@@ -307,7 +317,6 @@ int vers;
struct utsname u;
int main_thread;
int fd;
- static thread_key_t key_call_key;
#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
#define TOTAL_TRIES 5 /* Number of tries */
@@ -315,12 +324,9 @@ int vers;
if ((main_thread = thr_main())) {
kcp = key_call_private_main;
} else {
- if (key_call_key == 0) {
- mutex_lock(&tsd_lock);
- if (key_call_key == 0)
- thr_keycreate(&key_call_key, key_call_destroy);
- mutex_unlock(&tsd_lock);
- }
+ if (thr_once(&key_call_once, key_call_init) != 0 ||
+ key_call_key_error != 0)
+ return ((CLIENT *) NULL);
kcp = (struct key_call_private *)thr_getspecific(key_call_key);
}
if (kcp == (struct key_call_private *)NULL) {
diff --git a/lib/libc/rpc/mt_misc.c b/lib/libc/rpc/mt_misc.c
index 6241611..7abcaed 100644
--- a/lib/libc/rpc/mt_misc.c
+++ b/lib/libc/rpc/mt_misc.c
@@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$");
#define proglst_lock __proglst_lock
#define rpcsoc_lock __rpcsoc_lock
#define svcraw_lock __svcraw_lock
-#define tsd_lock __tsd_lock
#define xprtlist_lock __xprtlist_lock
/* protects the services list (svc.c) */
@@ -76,33 +75,33 @@ pthread_mutex_t rpcsoc_lock = PTHREAD_MUTEX_INITIALIZER;
/* svc_raw.c serialization */
pthread_mutex_t svcraw_lock = PTHREAD_MUTEX_INITIALIZER;
-/* protects TSD key creation */
-pthread_mutex_t tsd_lock = PTHREAD_MUTEX_INITIALIZER;
-
/* xprtlist (svc_generic.c) */
pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER;
#undef rpc_createerr
struct rpc_createerr rpc_createerr;
+static thread_key_t rce_key;
+static once_t rce_once = ONCE_INITIALIZER;
+static int rce_key_error;
+
+static void
+rce_key_init(void)
+{
+
+ rce_key_error = thr_keycreate(&rce_key, free);
+}
struct rpc_createerr *
__rpc_createerr()
{
- static thread_key_t rce_key = 0;
struct rpc_createerr *rce_addr = 0;
if (thr_main())
return (&rpc_createerr);
- if ((rce_addr =
- (struct rpc_createerr *)thr_getspecific(rce_key)) != 0) {
- mutex_lock(&tsd_lock);
- if (thr_keycreate(&rce_key, free) != 0) {
- mutex_unlock(&tsd_lock);
- return (&rpc_createerr);
- }
- mutex_unlock(&tsd_lock);
- }
+ if (thr_once(&rce_once, rce_key_init) != 0 || rce_key_error != 0)
+ return (&rpc_createerr);
+ rce_addr = (struct rpc_createerr *)thr_getspecific(rce_key);
if (!rce_addr) {
rce_addr = (struct rpc_createerr *)
malloc(sizeof (struct rpc_createerr));
diff --git a/lib/libc/rpc/mt_misc.h b/lib/libc/rpc/mt_misc.h
index e785c30..9cc2349 100644
--- a/lib/libc/rpc/mt_misc.h
+++ b/lib/libc/rpc/mt_misc.h
@@ -42,7 +42,6 @@
#define proglst_lock __proglst_lock
#define rpcsoc_lock __rpcsoc_lock
#define svcraw_lock __svcraw_lock
-#define tsd_lock __tsd_lock
#define xprtlist_lock __xprtlist_lock
extern pthread_rwlock_t svc_lock;
diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c
index 81bd92b..1bd7e15 100644
--- a/lib/libc/rpc/rpc_generic.c
+++ b/lib/libc/rpc/rpc_generic.c
@@ -221,6 +221,18 @@ getnettype(nettype)
return (_rpctypelist[i].type);
}
+static thread_key_t tcp_key, udp_key;
+static once_t keys_once = ONCE_INITIALIZER;
+static int tcp_key_error, udp_key_error;
+
+static void
+keys_init(void)
+{
+
+ tcp_key_error = thr_keycreate(&tcp_key, free);
+ udp_key_error = thr_keycreate(&udp_key, free);
+}
+
/*
* For the given nettype (tcp or udp only), return the first structure found.
* This should be freed by calling freenetconfigent()
@@ -242,19 +254,10 @@ __rpc_getconfip(nettype)
netid_udp = netid_udp_main;
netid_tcp = netid_tcp_main;
} else {
- if (tcp_key == 0) {
- mutex_lock(&tsd_lock);
- if (tcp_key == 0)
- thr_keycreate(&tcp_key, free);
- mutex_unlock(&tsd_lock);
- }
+ if (thr_once(&keys_once, keys_init) != 0 ||
+ tcp_key_error != 0 || udp_key_error != 0)
+ return (NULL);
netid_tcp = (char *)thr_getspecific(tcp_key);
- if (udp_key == 0) {
- mutex_lock(&tsd_lock);
- if (udp_key == 0)
- thr_keycreate(&udp_key, free);
- mutex_unlock(&tsd_lock);
- }
netid_udp = (char *)thr_getspecific(udp_key);
}
if (!netid_udp && !netid_tcp) {
diff --git a/lib/libc/rpc/rpc_soc.c b/lib/libc/rpc/rpc_soc.c
index 5922063..2568d43 100644
--- a/lib/libc/rpc/rpc_soc.c
+++ b/lib/libc/rpc/rpc_soc.c
@@ -360,6 +360,14 @@ registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
*/
static thread_key_t clnt_broadcast_key;
static resultproc_t clnt_broadcast_result_main;
+static once_t clnt_broadcast_once = ONCE_INITIALIZER;
+
+static void
+clnt_broadcast_key_init(void)
+{
+
+ thr_keycreate(&clnt_broadcast_key, free);
+}
/*
* Need to translate the netbuf address into sockaddr_in address.
@@ -402,12 +410,7 @@ clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
if (thr_main())
clnt_broadcast_result_main = eachresult;
else {
- if (clnt_broadcast_key == 0) {
- mutex_lock(&tsd_lock);
- if (clnt_broadcast_key == 0)
- thr_keycreate(&clnt_broadcast_key, free);
- mutex_unlock(&tsd_lock);
- }
+ thr_once(&clnt_broadcast_once, clnt_broadcast_key_init);
thr_setspecific(clnt_broadcast_key, (void *) eachresult);
}
return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
OpenPOWER on IntegriCloud