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
This commit is contained in:
John Baldwin 2010-03-10 13:23:25 +00:00
parent b911c45c24
commit 6f88d2a870
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=204950
8 changed files with 81 additions and 64 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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