git: 030acb63d9a8 - stable/13 - nfsd: Limit parsing of layout errors to maxcnt bytes

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Mon, 27 Dec 2021 00:57:08 UTC
The branch stable/13 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=030acb63d9a86b9a7bd15b06e60699abfa8a0a2b

commit 030acb63d9a86b9a7bd15b06e60699abfa8a0a2b
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2021-12-13 23:21:31 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2021-12-27 00:53:50 +0000

    nfsd: Limit parsing of layout errors to maxcnt bytes
    
    This patch decrements maxcnt by the appropriate
    number of bytes during parsing and checks to see
    if there is data remaining.  If not, it just returns
    from nfsrv_flexlayouterr() without further processing.
    This prevents the tl pointer from running off the end
    of the error data pointed at by layp, if there are
    flaws in the data.
    
    PR:     260293
    
    (cherry picked from commit c302f889e21f73746a3b0917df5246e639df1481)
---
 sys/fs/nfsserver/nfs_nfsdstate.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c
index 67f615ecea7c..1d0884683904 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -7001,14 +7001,25 @@ nfsrv_flexlayouterr(struct nfsrv_descript *nd, uint32_t *layp, int maxcnt,
 	char devid[NFSX_V4DEVICEID];
 
 	tl = layp;
-	cnt = fxdr_unsigned(int, *tl++);
+	maxcnt -= NFSX_UNSIGNED;
+	if (maxcnt > 0)
+		cnt = fxdr_unsigned(int, *tl++);
+	else
+		cnt = 0;
 	NFSD_DEBUG(4, "flexlayouterr cnt=%d\n", cnt);
 	for (i = 0; i < cnt; i++) {
+		maxcnt -= NFSX_STATEID + 2 * NFSX_HYPER +
+		    NFSX_UNSIGNED;
+		if (maxcnt <= 0)
+			break;
 		/* Skip offset, length and stateid for now. */
 		tl += (4 + NFSX_STATEID / NFSX_UNSIGNED);
 		errcnt = fxdr_unsigned(int, *tl++);
 		NFSD_DEBUG(4, "flexlayouterr errcnt=%d\n", errcnt);
 		for (j = 0; j < errcnt; j++) {
+			maxcnt -= NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED;
+			if (maxcnt < 0)
+				break;
 			NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
 			tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 			stat = fxdr_unsigned(int, *tl++);