Updated to the latest upstream RC release: libtirpc-1-3-3-rc5

Signed-off-by: Steve Dickson <steved@redhat.com>
This commit is contained in:
Steve Dickson 2022-08-01 15:26:12 -04:00
parent b4a233e957
commit f4b7939142
2 changed files with 322 additions and 11 deletions

View File

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

View File

@ -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 <steved@redhat.com> - 1.3.2-1.rc5
- Updated to the latest upstream RC release: libtirpc-1-3-3-rc5
* Thu Jul 28 2022 Steve Dickson <steved@redhat.com> - 1.3.2-1.rc4
- Updated to the latest upstream RC release: libtirpc-1-3-3-rc4