* [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
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ 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] 7+ 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
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ 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] 7+ messages in thread