All of lore.kernel.org
 help / color / mirror / Atom feed
* [rpcbind PATCH 0/6] rpcbind: various hardening fixes
@ 2026-09-03 17:42 Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 1/6] rpcbind: only log failures in check_callit() if connection logging is enabled Scott Mayhew
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

Various hardening fixes for rpcbind.  Many of these are related to
CALLIT/BCAST/INDIRECT processing, which in theory should be disabled
when --enable-rmtcalls was not passed to the configure script, except
currently that only prevents the forwarding port from being created.
Patch 3/6 addresses this by completely disabling remote call
functionality when --enable-rmtcalls is unset.

Scott Mayhew (6):
  rpcbind: only log failures in check_callit() if connection logging is
    enabled
  rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall()
  rpcbind: fully disable remote calls when --enable-rmtcalls is unset
  rpcbind: restrict RPCBPROC_GETSTAT to loopback callers
  rpcbind: check for null netmask in addrmerge()
  rpcbind: only free the forward slot if the reply xid matched the
    request xid

 src/pmap_svc.c     |  2 ++
 src/rpcb_stat.c    | 37 ++++++++++++++++++++++++++++++++++---
 src/rpcb_svc.c     |  2 ++
 src/rpcb_svc_4.c   |  2 ++
 src/rpcb_svc_com.c | 24 ++++++++++++++++++++----
 src/rpcbind.h      |  5 +++++
 src/security.c     | 16 +++++++++++-----
 src/util.c         |  3 ++-
 8 files changed, 78 insertions(+), 13 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 1/6] rpcbind: only log failures in check_callit() if connection logging is enabled
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 2/6] rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall() Scott Mayhew
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

logit() forks a child process to call syslog().  A client can spam
CALLIT/BROADCAST/INDIRECT requests, leading to CPU, scheduler, and PID
pressure.  It's better to only log failures from check_callit() if
rpcbind is running with the '-l' option (connection logging).

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/security.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/security.c b/src/security.c
index 38967dd..02651d7 100644
--- a/src/security.c
+++ b/src/security.c
@@ -343,11 +343,13 @@ check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum /*__unused*
 	return 1;
 deny:
 #ifdef LIBWRAP
-	logit(deny_severity, sa, args->rmt_proc, args->rmt_prog,
-	    ": indirect call not allowed");
+	if (verboselog)
+		logit(deny_severity, sa, args->rmt_proc, args->rmt_prog,
+		      ": indirect call not allowed");
 #else
-	logit(LOG_AUTH|LOG_WARNING, sa, args->rmt_proc, args->rmt_prog,
-	    ": indirect call not allowed");
+	if (verboselog)
+		logit(LOG_AUTH|LOG_WARNING, sa, args->rmt_proc, args->rmt_prog,
+		      ": indirect call not allowed");
 #endif
 	return 0;
 }
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 2/6] rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall()
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 1/6] rpcbind: only log failures in check_callit() if connection logging is enabled Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 3/6] rpcbind: fully disable remote calls when --enable-rmtcalls is unset Scott Mayhew
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

Limit addrinfo and rmtinfo linked lists to 4096 entries by trimming
the oldest entries from the tail after prepending a new one. This
prevents unbounded memory growth from a large number of unique
program/version/netid combinations.

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/rpcb_stat.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/rpcb_stat.c b/src/rpcb_stat.c
index 2e5226c..0799a47 100644
--- a/src/rpcb_stat.c
+++ b/src/rpcb_stat.c
@@ -50,6 +50,8 @@
 #include <string.h>
 #include "rpcbind.h"
 
+#define MAX_STAT_BUCKETS 4096
+
 static rpcb_stat_byvers inf;
 
 void
@@ -104,8 +106,9 @@ void
 rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
 	      char *uaddr)
 {
-	rpcbs_addrlist *al;
+	rpcbs_addrlist *al, *cut = NULL, *tmp;
 	struct netconfig *nconf;
+	int listlen = 0;
 
 	if (rtype >= RPCBVERS_STAT)
 		return;
@@ -121,6 +124,9 @@ rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
 				al->success++;
 			return;
 		}
+		listlen++;
+		if (listlen == MAX_STAT_BUCKETS - 1)
+			cut = al;
 	}
 	nconf = rpcbind_get_conf(netid);
 	if (nconf == NULL) {
@@ -142,14 +148,25 @@ rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
 	}
 	al->next = inf[rtype].addrinfo;
 	inf[rtype].addrinfo = al;
+
+	if (cut) {
+		al = cut->next;
+		cut->next = NULL;
+		while (al) {
+			tmp = al;
+			al = al->next;
+			free(tmp);
+		}
+	}
 }
 
 void
 rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
 	      rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl)
 {
-	rpcbs_rmtcalllist *rl;
+	rpcbs_rmtcalllist *rl, *cut = NULL, *tmp;
 	struct netconfig *nconf;
+	int listlen = 0;
 
 	if (rtype >= RPCBVERS_STAT)
 		return;
@@ -170,6 +187,9 @@ rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
 				rl->indirect++;
 			return;
 		}
+		listlen++;
+		if (listlen == MAX_STAT_BUCKETS - 1)
+			cut = rl;
 	}
 	nconf = rpcbind_get_conf(netid);
 	if (nconf == NULL) {
@@ -194,7 +214,16 @@ rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
 	rl->indirect = 1;
 	rl->next = inf[rtype].rmtinfo;
 	inf[rtype].rmtinfo = rl;
-	return;
+
+	if (cut) {
+		rl = cut->next;
+		cut->next = NULL;
+		while (rl) {
+			tmp = rl;
+			rl = rl->next;
+			free(tmp);
+		}
+	}
 }
 
 void *
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 3/6] rpcbind: fully disable remote calls when --enable-rmtcalls is unset
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 1/6] rpcbind: only log failures in check_callit() if connection logging is enabled Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 2/6] rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall() Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 4/6] rpcbind: restrict RPCBPROC_GETSTAT to loopback callers Scott Mayhew
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

Commit 2e9c289 ("rpcbind: Disable remote calls by default") added the
'--enable-rmtcalls' option, which is off by default, but that only
suppresses the creation of the rmtcallfd for a given netconfig entry.

In this case a client can still send rpcbind CALLIT/BCAST/INDIRECT
requests, which will eventually bail out in rpcbproc_callit_com() after
find_rmtcallfd_by_netid() fails... but by that point rpcbind may have
called logit() (which forks a child process) or rpcbs_rmtcall() (which
allocates a stats bucket if the request contained a unique program or
procedure number).

If configure is run without the '--enable-rmtcalls' option, then fully
disable remote call functionality.  Attempts to call
CALLIT/BCAST/INDIRECT will receive an accept state of PROC_UNAVAIL.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/pmap_svc.c     |  2 ++
 src/rpcb_stat.c    |  2 ++
 src/rpcb_svc.c     |  2 ++
 src/rpcb_svc_4.c   |  2 ++
 src/rpcb_svc_com.c | 19 ++++++++++++++++---
 src/rpcbind.h      |  5 +++++
 src/security.c     |  4 ++++
 7 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/src/pmap_svc.c b/src/pmap_svc.c
index e5a5d0f..27091ac 100644
--- a/src/pmap_svc.c
+++ b/src/pmap_svc.c
@@ -125,6 +125,7 @@ pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
 		pmapproc_dump(rqstp, xprt);
 		break;
 
+#ifdef RMTCALLS
 	case PMAPPROC_CALLIT:
 		/*
 		 * Calls a procedure on the local machine. If the requested
@@ -135,6 +136,7 @@ pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
 		 */
 		rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
 		break;
+#endif /* RMTCALLS */
 
 	default:
 		svcerr_noproc(xprt);
diff --git a/src/rpcb_stat.c b/src/rpcb_stat.c
index 0799a47..ef2b3a9 100644
--- a/src/rpcb_stat.c
+++ b/src/rpcb_stat.c
@@ -160,6 +160,7 @@ rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
 	}
 }
 
+#ifdef RMTCALLS
 void
 rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
 	      rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl)
@@ -225,6 +226,7 @@ rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
 		}
 	}
 }
+#endif /* RMTCALLS */
 
 void *
 rpcbproc_getstat(void *arg /*__unused*/, struct svc_req *req /*__unused*/,
diff --git a/src/rpcb_svc.c b/src/rpcb_svc.c
index 091f530..e52e82f 100644
--- a/src/rpcb_svc.c
+++ b/src/rpcb_svc.c
@@ -122,9 +122,11 @@ rpcb_service_3(struct svc_req *rqstp, SVCXPRT *transp)
 		local = rpcbproc_dump_3_local;
 		break;
 
+#ifdef RMTCALLS
 	case RPCBPROC_CALLIT:
 		rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS);
 		return;
+#endif /* RMTCALLS */
 
 	case RPCBPROC_GETTIME:
 #ifdef RPCBIND_DEBUG
diff --git a/src/rpcb_svc_4.c b/src/rpcb_svc_4.c
index eebbbbe..dbb8839 100644
--- a/src/rpcb_svc_4.c
+++ b/src/rpcb_svc_4.c
@@ -141,6 +141,7 @@ rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp)
 		local = rpcbproc_dump_4_local;
 		break;
 
+#ifdef RMTCALLS
 	case RPCBPROC_INDIRECT:
 #ifdef RPCBIND_DEBUG
 		if (debugging)
@@ -157,6 +158,7 @@ rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp)
 #endif
 		rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
 		return;
+#endif /* RMTCALLS */
 
 	case RPCBPROC_GETTIME:
 #ifdef RPCBIND_DEBUG
diff --git a/src/rpcb_svc_com.c b/src/rpcb_svc_com.c
index 6d0d72d..0763fc4 100644
--- a/src/rpcb_svc_com.c
+++ b/src/rpcb_svc_com.c
@@ -74,6 +74,8 @@
 
 
 static char *nullstring = "";
+
+#ifdef RMTCALLS
 static int rpcb_rmtcalls;
 
 struct rmtcallfd_list {
@@ -120,6 +122,8 @@ static void xprt_set_caller(SVCXPRT *, struct finfo *);
 static void send_svcsyserr(SVCXPRT *, struct finfo *);
 static void handle_reply(int, SVCXPRT *);
 static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
+#endif /* RMTCALLS */
+
 static rpcblist_ptr find_service(rpcprog_t, rpcvers_t, char *);
 static char *getowner(SVCXPRT *, char *, size_t);
 static int add_pmaplist(RPCB *);
@@ -429,7 +433,7 @@ rpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp /*__unused*/,
 	return (void *)&uaddr;
 }
 
-
+#ifdef RMTCALLS
 static bool_t
 xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
 {
@@ -1048,12 +1052,15 @@ netbuffree(struct netbuf *ap)
 	free(ap->buf);
 	free(ap);
 }
-
+#endif /* RMTCALLS */
 
 void
 my_svc_run()
 {
-	int poll_ret, check_ret;
+	int poll_ret;
+#ifdef RMTCALLS
+	int check_ret;
+#endif /* RMTCALLS */
 
 	for (;;) {
 	        struct pollfd my_pollfd[svc_max_pollfd];
@@ -1087,14 +1094,19 @@ my_svc_run()
 			 * don't call svc_getreq_poll.  Otherwise, there
 			 * must be another so we must call svc_getreq_poll.
 			 */
+#ifdef RMTCALLS
 			if ((check_ret = check_rmtcalls(my_pollfd, svc_max_pollfd)) ==
 			    poll_ret)
 				continue;
 			svc_getreq_poll(my_pollfd, poll_ret-check_ret);
+#else
+			svc_getreq_poll(my_pollfd, poll_ret);
+#endif /* RMTCALLS */
 		}
 	}
 }
 
+#ifdef RMTCALLS
 static int
 check_rmtcalls(struct pollfd *pfds, int nfds)
 {
@@ -1289,6 +1301,7 @@ find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
 	*highvp = highv;
 	return;
 }
+#endif /* RMTCALLS */
 
 /*
  * returns the item with the given program, version number and netid.
diff --git a/src/rpcbind.h b/src/rpcbind.h
index 5b1a9bb..ef3aab8 100644
--- a/src/rpcbind.h
+++ b/src/rpcbind.h
@@ -89,8 +89,10 @@ void rpcbs_procinfo(rpcvers_t, rpcproc_t);
 void rpcbs_set(rpcvers_t, bool_t);
 void rpcbs_unset(rpcvers_t, bool_t);
 void rpcbs_getaddr(rpcvers_t, rpcprog_t, rpcvers_t, char *, char *);
+#ifdef RMTCALLS
 void rpcbs_rmtcall(rpcvers_t, rpcproc_t, rpcprog_t, rpcvers_t, rpcproc_t,
 			char *, rpcblist_ptr);
+#endif /* RMTCALLS */
 void *rpcbproc_getstat(void *, struct svc_req *, SVCXPRT *, rpcvers_t);
 
 void rpcb_service_3(struct svc_req *, SVCXPRT *);
@@ -110,9 +112,12 @@ void *rpcbproc_uaddr2taddr_com(void *, struct svc_req *,
 					     SVCXPRT *, rpcvers_t);
 void *rpcbproc_taddr2uaddr_com(void *, struct svc_req *, SVCXPRT *,
 				    rpcvers_t);
+#ifdef RMTCALLS
 int create_rmtcall_fd(struct netconfig *);
 void rpcbproc_callit_com(struct svc_req *, SVCXPRT *, rpcvers_t,
 			      rpcvers_t);
+#endif /* RMTCALLS */
+
 void my_svc_run(void);
 
 void rpcbind_abort(void);
diff --git a/src/security.c b/src/security.c
index 02651d7..6bd22fd 100644
--- a/src/security.c
+++ b/src/security.c
@@ -99,8 +99,10 @@ check_access(SVCXPRT *xprt, rpcproc_t proc, rpcprog_t prog, unsigned int rpcbver
 		}
 		break;
 	case RPCBPROC_GETADDR:
+#ifdef RMTCALLS
 	case RPCBPROC_CALLIT:
 	case RPCBPROC_INDIRECT:
+#endif /* RMTCALLS */
 	case RPCBPROC_DUMP:
 	case RPCBPROC_GETTIME:
 	case RPCBPROC_UADDR2TADDR:
@@ -290,6 +292,7 @@ logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum,
 	}
 }
 
+#ifdef RMTCALLS
 int
 check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum /*__unused*/)
 {
@@ -353,3 +356,4 @@ deny:
 #endif
 	return 0;
 }
+#endif /* RMTCALLS */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 4/6] rpcbind: restrict RPCBPROC_GETSTAT to loopback callers
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
                   ` (2 preceding siblings ...)
  2026-09-03 17:42 ` [rpcbind PATCH 3/6] rpcbind: fully disable remote calls when --enable-rmtcalls is unset Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 5/6] rpcbind: check for null netmask in addrmerge() Scott Mayhew
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

There's no reason to allow remote machines to query the local machine's
rpcbind statistics.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/security.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/security.c b/src/security.c
index 6bd22fd..3b55151 100644
--- a/src/security.c
+++ b/src/security.c
@@ -87,6 +87,7 @@ check_access(SVCXPRT *xprt, rpcproc_t proc, rpcprog_t prog, unsigned int rpcbver
 	switch (proc) {
 	case RPCBPROC_SET:
 	case RPCBPROC_UNSET:
+	case RPCBPROC_GETSTAT:
 		if (!insecure && !is_loopback(caller)) {
 #ifdef RPCBIND_DEBUG
 			  if (debugging)
@@ -109,7 +110,6 @@ check_access(SVCXPRT *xprt, rpcproc_t proc, rpcprog_t prog, unsigned int rpcbver
 	case RPCBPROC_TADDR2UADDR:
 	case RPCBPROC_GETVERSADDR:
 	case RPCBPROC_GETADDRLIST:
-	case RPCBPROC_GETSTAT:
 	default:
 		break;
 	}
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 5/6] rpcbind: check for null netmask in addrmerge()
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
                   ` (3 preceding siblings ...)
  2026-09-03 17:42 ` [rpcbind PATCH 4/6] rpcbind: restrict RPCBPROC_GETSTAT to loopback callers Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-03 17:42 ` [rpcbind PATCH 6/6] rpcbind: only free the forward slot if the reply xid matched the request xid Scott Mayhew
  2026-09-12 14:32 ` [rpcbind PATCH 0/6] rpcbind: various hardening fixes Steve Dickson
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

getifaddrs(3) states that ifa_netmask may contain a null pointer, so we
should skip interfaces where ifa_netmask is null to avoid triggering a
null dereference in bitmaskcmp().

This is mainly a defensive change - we only call bitmaskcmp() for
AF_INET/AF_INET6 addresses, and I'm not sure it's possible for an
interface to have an IP address but no netmask.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/util.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/util.c b/src/util.c
index ead4899..a61a8c6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -165,7 +165,8 @@ addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
 		ifsa = ifap->ifa_addr;
 		ifmasksa = ifap->ifa_netmask;
 
-		if (ifsa == NULL || ifsa->sa_family != hint_sa->sa_family ||
+		if (ifsa == NULL || ifmasksa == NULL ||
+		    ifsa->sa_family != hint_sa->sa_family ||
 		    !(ifap->ifa_flags & IFF_UP))
 			continue;
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [rpcbind PATCH 6/6] rpcbind: only free the forward slot if the reply xid matched the request xid
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
                   ` (4 preceding siblings ...)
  2026-09-03 17:42 ` [rpcbind PATCH 5/6] rpcbind: check for null netmask in addrmerge() Scott Mayhew
@ 2026-09-03 17:42 ` Scott Mayhew
  2026-09-12 14:32 ` [rpcbind PATCH 0/6] rpcbind: various hardening fixes Steve Dickson
  6 siblings, 0 replies; 8+ messages in thread
From: Scott Mayhew @ 2026-09-03 17:42 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs

If remote calls are enabled and if the ephemeral forwarding ports are
exposed, it's possible to spoof replies to forwarded requests using a
bogus xid, causing the forward slots to be freed and potentially
interfering with sending replies to legitimate remote call requesters.

Only free the forward slot in handle_reply() if the reply xid matched
the original request xid.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/rpcb_svc_com.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/rpcb_svc_com.c b/src/rpcb_svc_com.c
index 0763fc4..2c007eb 100644
--- a/src/rpcb_svc_com.c
+++ b/src/rpcb_svc_com.c
@@ -1196,6 +1196,7 @@ handle_reply(int fd, SVCXPRT *xprt)
 	struct r_rmtcall_args a;
 	struct sockaddr_storage ss;
 	socklen_t fromlen;
+	bool_t matched_xid = FALSE;
 
 	buffer = malloc(RPC_BUF_MAX);
 	if (buffer == NULL)
@@ -1234,6 +1235,7 @@ handle_reply(int fd, SVCXPRT *xprt)
 	if (fi == NULL) {
 		goto done;
 	}
+	matched_xid = TRUE;
 	_seterr_reply(&reply_msg, &reply_error);
 	if (reply_error.re_status != RPC_SUCCESS) {
 		if (debugging)
@@ -1271,7 +1273,8 @@ done:
 		xlog(LOG_DEBUG, "handle_reply:  NULL xid on exit!\n");
 	}
 #endif
-	} else
+	}
+	if (matched_xid == TRUE)
 		(void) free_slot_by_xid(reply_msg.rm_xid);
 	return;
 }
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [rpcbind PATCH 0/6] rpcbind: various hardening fixes
  2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
                   ` (5 preceding siblings ...)
  2026-09-03 17:42 ` [rpcbind PATCH 6/6] rpcbind: only free the forward slot if the reply xid matched the request xid Scott Mayhew
@ 2026-09-12 14:32 ` Steve Dickson
  6 siblings, 0 replies; 8+ messages in thread
From: Steve Dickson @ 2026-09-12 14:32 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: linux-nfs



On 9/3/26 1:42 PM, Scott Mayhew wrote:
> Various hardening fixes for rpcbind.  Many of these are related to
> CALLIT/BCAST/INDIRECT processing, which in theory should be disabled
> when --enable-rmtcalls was not passed to the configure script, except
> currently that only prevents the forwarding port from being created.
> Patch 3/6 addresses this by completely disabling remote call
> functionality when --enable-rmtcalls is unset.
> 
> Scott Mayhew (6):
>    rpcbind: only log failures in check_callit() if connection logging is
>      enabled
>    rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall()
>    rpcbind: fully disable remote calls when --enable-rmtcalls is unset
>    rpcbind: restrict RPCBPROC_GETSTAT to loopback callers
>    rpcbind: check for null netmask in addrmerge()
>    rpcbind: only free the forward slot if the reply xid matched the
>      request xid
> 
>   src/pmap_svc.c     |  2 ++
>   src/rpcb_stat.c    | 37 ++++++++++++++++++++++++++++++++++---
>   src/rpcb_svc.c     |  2 ++
>   src/rpcb_svc_4.c   |  2 ++
>   src/rpcb_svc_com.c | 24 ++++++++++++++++++++----
>   src/rpcbind.h      |  5 +++++
>   src/security.c     | 16 +++++++++++-----
>   src/util.c         |  3 ++-
>   8 files changed, 78 insertions(+), 13 deletions(-)
> 
Committed... (tag: rpcbind-1_2_9-rc3)

steved.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-12 14:32 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 17:42 [rpcbind PATCH 0/6] rpcbind: various hardening fixes Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 1/6] rpcbind: only log failures in check_callit() if connection logging is enabled Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 2/6] rpcbind: bound stats lists in rpcbs_getaddr() and rpcbs_rmtcall() Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 3/6] rpcbind: fully disable remote calls when --enable-rmtcalls is unset Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 4/6] rpcbind: restrict RPCBPROC_GETSTAT to loopback callers Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 5/6] rpcbind: check for null netmask in addrmerge() Scott Mayhew
2026-09-03 17:42 ` [rpcbind PATCH 6/6] rpcbind: only free the forward slot if the reply xid matched the request xid Scott Mayhew
2026-09-12 14:32 ` [rpcbind PATCH 0/6] rpcbind: various hardening fixes Steve Dickson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.