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:
parent
42dc39ae95
commit
e0724fd324
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user