git: 9d13c87afdb3 - main - nfs_clrpcops.c: NFSM_DISSECT() reply for each dir separately

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 28 Oct 2025 21:34:23 UTC
The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=9d13c87afdb35c0014aa6f43c5652e946c18b756

commit 9d13c87afdb35c0014aa6f43c5652e946c18b756
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-10-28 21:31:30 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-10-28 21:31:30 +0000

    nfs_clrpcops.c: NFSM_DISSECT() reply for each dir separately
    
    Without this patch, the entire reply for all directories in
    the NFSv4 mount path are parsed at once.  This could cause
    problems for mount paths with many directories in the path.
    
    This patch fixes the problem by parsing each directory
    reply in a loop.
    
    Spotted while fixing other cases that could do large
    NFSM_DISSECT() sizes.
    
    MFC after:      3 days
---
 sys/fs/nfsclient/nfs_clrpcops.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 983eb8b9226f..b88169ba69d5 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -5284,7 +5284,7 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
 	struct nfsrv_descript nfsd;
 	struct nfsrv_descript *nd = &nfsd;
 	u_char *cp, *cp2, *fhp;
-	int error, cnt, len, setnil;
+	int error, cnt, i, len, setnil;
 	u_int32_t *opcntp;
 
 	nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
@@ -5325,8 +5325,12 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
 	if (error)
 		return (error);
 	if (nd->nd_repstat == 0) {
-		NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
-		tl += (2 + 2 * cnt);
+		NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+		tl += 2;
+		for (i = 0; i < cnt; i++) {
+			NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+			tl++;
+		}
 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
 			len > NFSX_FHMAX) {
 			nd->nd_repstat = NFSERR_BADXDR;