diff --git a/libtirpc-1.3.3-rc4.patch b/libtirpc-1.3.3-rc5.patch similarity index 85% rename from libtirpc-1.3.3-rc4.patch rename to libtirpc-1.3.3-rc5.patch index 5c0c743..c60d30e 100644 --- a/libtirpc-1.3.3-rc4.patch +++ b/libtirpc-1.3.3-rc5.patch @@ -1178,6 +1178,19 @@ index a07e297..5bbc78b 100644 if (ct->ct_closeit && ct->ct_fd != -1) { (void)close(ct->ct_fd); } +diff --git a/src/mt_misc.c b/src/mt_misc.c +index 5a49b78..3a2bc51 100644 +--- a/src/mt_misc.c ++++ b/src/mt_misc.c +@@ -13,7 +13,7 @@ pthread_rwlock_t svc_lock = PTHREAD_RWLOCK_INITIALIZER; + pthread_rwlock_t svc_fd_lock = PTHREAD_RWLOCK_INITIALIZER; + + /* protects the RPCBIND address cache */ +-pthread_rwlock_t rpcbaddr_cache_lock = PTHREAD_RWLOCK_INITIALIZER; ++pthread_mutex_t rpcbaddr_cache_lock = PTHREAD_MUTEX_INITIALIZER; + + /* protects authdes cache (svcauth_des.c) */ + pthread_mutex_t authdes_lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/src/rpc_dtablesize.c b/src/rpc_dtablesize.c index 3fe503a..bce97e8 100644 --- a/src/rpc_dtablesize.c @@ -1192,10 +1205,305 @@ index 3fe503a..bce97e8 100644 return (size); } diff --git a/src/rpcb_clnt.c b/src/rpcb_clnt.c -index 0c34cb7..06f4528 100644 +index 0c34cb7..1b5b04c 100644 --- a/src/rpcb_clnt.c +++ b/src/rpcb_clnt.c -@@ -798,6 +798,10 @@ __try_protocol_version_2(program, version, nconf, host, tp) +@@ -85,7 +85,7 @@ static int cachesize; + + extern int __rpc_lowvers; + +-static struct address_cache *check_cache(const char *, const char *); ++static struct address_cache *copy_of_cached(const char *, char *); + static void delete_cache(struct netbuf *); + static void add_cache(const char *, const char *, struct netbuf *, char *); + static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); +@@ -94,6 +94,82 @@ static CLIENT *local_rpcb(void); + static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); + #endif + ++/* ++ * Destroys a cached address entry structure. ++ * ++ */ ++static void ++destroy_addr(addr) ++ struct address_cache *addr; ++{ ++ if (addr == NULL) ++ return; ++ if(addr->ac_host != NULL) ++ free(addr->ac_host); ++ if(addr->ac_netid != NULL) ++ free(addr->ac_netid); ++ if(addr->ac_uaddr != NULL) ++ free(addr->ac_uaddr); ++ if(addr->ac_taddr != NULL) { ++ if(addr->ac_taddr->buf != NULL) ++ free(addr->ac_taddr->buf); ++ } ++ free(addr); ++} ++ ++/* ++ * Creates an unlinked copy of an address cache entry. If the argument is NULL ++ * or the new entry cannot be allocated then NULL is returned. ++ */ ++static struct address_cache * ++copy_addr(addr) ++ const struct address_cache *addr; ++{ ++ struct address_cache *copy; ++ ++ if (addr == NULL) ++ return (NULL); ++ ++ copy = calloc(1, sizeof(*addr)); ++ if (copy == NULL) ++ return (NULL); ++ ++ if (addr->ac_host != NULL) { ++ copy->ac_host = strdup(addr->ac_host); ++ if (copy->ac_host == NULL) ++ goto err; ++ } ++ if (addr->ac_netid != NULL) { ++ copy->ac_netid = strdup(addr->ac_netid); ++ if (copy->ac_netid == NULL) ++ goto err; ++ } ++ if (addr->ac_uaddr != NULL) { ++ copy->ac_uaddr = strdup(addr->ac_uaddr); ++ if (copy->ac_uaddr == NULL) ++ goto err; ++ } ++ ++ if (addr->ac_taddr == NULL) ++ return (copy); ++ ++ copy->ac_taddr = calloc(1, sizeof(*addr->ac_taddr)); ++ if (copy->ac_taddr == NULL) ++ goto err; ++ ++ memcpy(copy->ac_taddr, addr->ac_taddr, sizeof(*addr->ac_taddr)); ++ copy->ac_taddr->buf = malloc(addr->ac_taddr->len); ++ if (copy->ac_taddr->buf == NULL) ++ goto err; ++ ++ memcpy(copy->ac_taddr->buf, addr->ac_taddr->buf, addr->ac_taddr->len); ++ return (copy); ++ ++err: ++ destroy_addr(copy); ++ return (NULL); ++} ++ + /* + * This routine adjusts the timeout used for calls to the remote rpcbind. + * Also, this routine can be used to set the use of portmapper version 2 +@@ -125,17 +201,18 @@ __rpc_control(request, info) + } + + /* +- * It might seem that a reader/writer lock would be more reasonable here. +- * However because getclnthandle(), the only user of the cache functions, +- * may do a delete_cache() operation if a check_cache() fails to return an +- * address useful to clnt_tli_create(), we may as well use a mutex. +- */ +-/* +- * As it turns out, if the cache lock is *not* a reader/writer lock, we will +- * block all clnt_create's if we are trying to connect to a host that's down, +- * since the lock will be held all during that time. ++ * Protect against concurrent access to the address cache and modifications ++ * (esp. deletions) of cache entries. ++ * ++ * Previously a bidirectional R/W lock was used. However, R/W locking is ++ * dangerous as it allows concurrent modification (e.g. deletion with write ++ * lock) at the same time as the deleted element is accessed via check_cache() ++ * and a read lock). We absolutely need a single mutex for all access to ++ * prevent cache corruption. If the mutexing is restricted to only the ++ * relevant code sections, deadlocking should be avoided even with recursed ++ * client creation. + */ +-extern rwlock_t rpcbaddr_cache_lock; ++extern pthread_mutex_t rpcbaddr_cache_lock; + + /* + * The routines check_cache(), add_cache(), delete_cache() manage the +@@ -143,49 +220,51 @@ extern rwlock_t rpcbaddr_cache_lock; + */ + + static struct address_cache * +-check_cache(host, netid) ++copy_of_cached(host, netid) + const char *host, *netid; + { +- struct address_cache *cptr; +- +- /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ ++ struct address_cache *cptr, *copy = NULL; + ++ mutex_lock(&rpcbaddr_cache_lock); + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!strcmp(cptr->ac_host, host) && + !strcmp(cptr->ac_netid, netid)) { + LIBTIRPC_DEBUG(3, ("check_cache: Found cache entry for %s: %s\n", + host, netid)); +- return (cptr); ++ copy = copy_addr(cptr); ++ break; + } + } +- return ((struct address_cache *) NULL); ++ mutex_unlock(&rpcbaddr_cache_lock); ++ return copy; + } + + static void + delete_cache(addr) + struct netbuf *addr; + { +- struct address_cache *cptr, *prevptr = NULL; ++ struct address_cache *cptr = NULL, *prevptr = NULL; ++ ++ /* LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ ++ mutex_lock(&rpcbaddr_cache_lock); + +- /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { +- free(cptr->ac_host); +- free(cptr->ac_netid); +- free(cptr->ac_taddr->buf); +- free(cptr->ac_taddr); ++ /* Unlink from cache. We'll destroy it after releasing the mutex. */ + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + if (prevptr) + prevptr->ac_next = cptr->ac_next; + else + front = cptr->ac_next; +- free(cptr); + cachesize--; + break; + } + prevptr = cptr; + } ++ ++ mutex_unlock(&rpcbaddr_cache_lock); ++ destroy_addr(cptr); + } + + static void +@@ -217,7 +296,7 @@ add_cache(host, netid, taddr, uaddr) + + /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ + +- rwlock_wrlock(&rpcbaddr_cache_lock); ++ mutex_lock(&rpcbaddr_cache_lock); + if (cachesize < CACHESIZE) { + ad_cache->ac_next = front; + front = ad_cache; +@@ -250,7 +329,7 @@ add_cache(host, netid, taddr, uaddr) + } + free(cptr); + } +- rwlock_unlock(&rpcbaddr_cache_lock); ++ mutex_unlock(&rpcbaddr_cache_lock); + return; + + out_free: +@@ -261,6 +340,7 @@ out_free: + free(ad_cache); + } + ++ + /* + * This routine will return a client handle that is connected to the + * rpcbind. If targaddr is non-NULL, the "universal address" of the +@@ -275,11 +355,9 @@ getclnthandle(host, nconf, targaddr) + char **targaddr; + { + CLIENT *client; +- struct netbuf *addr, taddr; +- struct netbuf addr_to_delete; ++ struct netbuf taddr; + struct __rpc_sockinfo si; + struct addrinfo hints, *res, *tres; +- struct address_cache *ad_cache; + char *tmpaddr; + + if (nconf == NULL) { +@@ -294,47 +372,35 @@ getclnthandle(host, nconf, targaddr) + return NULL; + } + +-/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ ++ + + /* Get the address of the rpcbind. Check cache first */ + client = NULL; + if (targaddr) + *targaddr = NULL; +- addr_to_delete.len = 0; +- rwlock_rdlock(&rpcbaddr_cache_lock); +- ad_cache = NULL; +- +- if (host != NULL) +- ad_cache = check_cache(host, nconf->nc_netid); +- if (ad_cache != NULL) { +- addr = ad_cache->ac_taddr; +- client = clnt_tli_create(RPC_ANYFD, nconf, addr, +- (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); +- if (client != NULL) { +- if (targaddr && ad_cache->ac_uaddr) +- *targaddr = strdup(ad_cache->ac_uaddr); +- rwlock_unlock(&rpcbaddr_cache_lock); +- return (client); +- } +- addr_to_delete.len = addr->len; +- addr_to_delete.buf = (char *)malloc(addr->len); +- if (addr_to_delete.buf == NULL) { +- addr_to_delete.len = 0; +- } else { +- memcpy(addr_to_delete.buf, addr->buf, addr->len); ++ ++ if (host != NULL) { ++ struct address_cache *ad_cache; ++ ++ /* Get an MT-safe copy of the cached address (if any) */ ++ ad_cache = copy_of_cached(host, nconf->nc_netid); ++ if (ad_cache != NULL) { ++ client = clnt_tli_create(RPC_ANYFD, nconf, ad_cache->ac_taddr, ++ (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); ++ if (client != NULL) { ++ if (targaddr && ad_cache->ac_uaddr) { ++ *targaddr = ad_cache->ac_uaddr; ++ ad_cache->ac_uaddr = NULL; /* De-reference before destruction */ ++ } ++ destroy_addr(ad_cache); ++ return (client); ++ } ++ ++ delete_cache(ad_cache->ac_taddr); ++ destroy_addr(ad_cache); + } + } +- rwlock_unlock(&rpcbaddr_cache_lock); +- if (addr_to_delete.len != 0) { +- /* +- * Assume this may be due to cache data being +- * outdated +- */ +- rwlock_wrlock(&rpcbaddr_cache_lock); +- delete_cache(&addr_to_delete); +- rwlock_unlock(&rpcbaddr_cache_lock); +- free(addr_to_delete.buf); +- } ++ + if (!__rpc_nconf2sockinfo(nconf, &si)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + assert(client == NULL); +@@ -798,6 +864,10 @@ __try_protocol_version_2(program, version, nconf, host, tp) pmapaddress->len = pmapaddress->maxlen = remote.len; CLNT_DESTROY(client); @@ -1206,7 +1514,7 @@ index 0c34cb7..06f4528 100644 return pmapaddress; error: -@@ -806,6 +810,10 @@ error: +@@ -806,6 +876,10 @@ error: client = NULL; } @@ -1217,7 +1525,7 @@ index 0c34cb7..06f4528 100644 return (NULL); } -@@ -818,7 +826,8 @@ error: +@@ -818,7 +892,8 @@ error: * The algorithm used: If the transports is TCP or UDP, it first tries * version 4 (srv4), then 3 and then fall back to version 2 (portmap). * With this algorithm, we get performance as well as a plan for @@ -1227,7 +1535,7 @@ index 0c34cb7..06f4528 100644 * * For all other transports, the algorithm remains as 4 and then 3. * -@@ -839,6 +848,10 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) +@@ -839,6 +914,10 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) #ifdef NOTUSED static bool_t check_rpcbind = TRUE; #endif @@ -1238,14 +1546,14 @@ index 0c34cb7..06f4528 100644 CLIENT *client = NULL; RPCB parms; enum clnt_stat clnt_st; -@@ -895,8 +908,18 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) +@@ -895,8 +974,18 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) parms.r_addr = (char *) &nullstring[0]; } - /* First try from start_vers(4) and then version 3 (RPCBVERS) */ + /* First try from start_vers(4) and then version 3 (RPCBVERS), except + * if env. var RPCB_V2FIRST is defined */ -+ + +#ifdef PORTMAP + if (getenv(V2FIRST)) { + portmap_first = TRUE; @@ -1253,12 +1561,12 @@ index 0c34cb7..06f4528 100644 + goto portmap; + } +#endif - ++ +rpcbind: CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); for (vers = start_vers; vers >= RPCBVERS; vers--) { /* Set the version */ -@@ -944,10 +967,17 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) +@@ -944,10 +1033,17 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) } #ifdef PORTMAP /* Try version 2 for TCP or UDP */ diff --git a/libtirpc.spec b/libtirpc.spec index 53dd587..b002cfa 100644 --- a/libtirpc.spec +++ b/libtirpc.spec @@ -2,13 +2,13 @@ Name: libtirpc Version: 1.3.2 -Release: 1.rc4%{?dist} +Release: 1.rc5%{?dist} Summary: Transport Independent RPC Library License: SISSL and BSD URL: http://git.linux-nfs.org/?p=steved/libtirpc.git;a=summary Source0: http://downloads.sourceforge.net/libtirpc/libtirpc-%{version}.tar.bz2 -Patch001: libtirpc-1.3.3-rc4.patch +Patch001: libtirpc-1.3.3-rc5.patch BuildRequires: automake, autoconf, libtool, pkgconfig BuildRequires: krb5-devel @@ -114,6 +114,9 @@ mv %{buildroot}%{_mandir}/man3 %{buildroot}%{_mandir}/man3t %{_mandir}/*/* %changelog +* Mon Aug 1 2022 Steve Dickson - 1.3.2-1.rc5 +- Updated to the latest upstream RC release: libtirpc-1-3-3-rc5 + * Thu Jul 28 2022 Steve Dickson - 1.3.2-1.rc4 - Updated to the latest upstream RC release: libtirpc-1-3-3-rc4