From nobody Sat Jul 18 01:16:54 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h28530mGwz6lq36 for ; Sat, 18 Jul 2026 01:16:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h285305TPz3XZh for ; Sat, 18 Jul 2026 01:16:55 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784337415; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BmQxGYwEjgs4dLhrLXB4BLq6ut3KUubnP01we73G7dM=; b=HSvMYr6oSe/qj4CItFFXJhQagzo7kTYoZNXghRuLQTC9FxeD5CetmK+1WEGOjMjJMNCryq SzHUEYbOrjwgaQCpRRXMj6TILSF0rTE6ENX4oDz/czbeQ1uGS+St8rHUcVrmTWHPHiZOWh lnrWzhZ+V4dlUUu37DSkggk8pPudXU4NojKVReeKT2ETM/vjD1Ir72kv5JhWVQLSucyf9g HGu1a4pgnXoPTTzLeDzMYE/a90v6uWOchcNw5lR/eTVsHbOMVj6jHQbOOgs9v+dwbghLJD xWOw77T7PsKQ2Udu2B/69EmI2wnYCG9rivwDyScbqfCuOvU/HMyVD+Cq42J7Mg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784337415; a=rsa-sha256; cv=none; b=E5/XmYqTZR7VzHkAl0b/Ss9Lxv8Sa77VJ7Fe8ysPQ1wuH5WA02EF7mVgnx7uW3PVaY0n1H GCz+DWExOmpEcrzKo0zwXXNFcWEbwxyWXjuXDCgbMtr+L0b7i4ysRnPsHElWNd2qkhUBhi 4+plnL431toeKHVwQXX9vs/hkSc3KLtzIO7xjJynFkKwb2e+CE205pVtt9BSjng+Ecvoi0 U5wxarw5mJGYUB09LO4vGWZKgQ6InYsPY36Z0iHaC/pYPggSZt2WVkwWjZlZ5do/6gsDq4 3+2HiagaMyTdeZgc59EC2Iom2ZsLhdZANOsIpniOu+k0H0ab92p+SHGXMftu/g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784337415; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BmQxGYwEjgs4dLhrLXB4BLq6ut3KUubnP01we73G7dM=; b=omkirjvg0690sEe6PHc+CaS5+30NikFpfRsx6aH2wXQfPWYbRPHwrHT0+kslzQ7hRMGPY8 f3PB2RNILIY9zvGdEdtJjrQY7XLbG5YBLpsbGA/x4Rq1ycx16TpumTt/mnjGtoKghoTOff l04uxze2SFjjWXw40BIrlNErX8EUh36NdOIDNizq5wwsFg3YvrrtV3eD7ZHtAiBS0xBw+y Ay3JsF8M7q2ZaX+nFTrdjvpUHw/14de4LkPrKATqk5TAmq0jB8brS5lYVmLtsRj+SHBfyb Eo+L+1Y6Ivk7/4fG4x1rWqr/TMkYBhe2Ny/n24AOa3u8kUHcsituNh1SjJ/CfA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h28525jF7z1BM5 for ; Sat, 18 Jul 2026 01:16:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 440a0 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 18 Jul 2026 01:16:54 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: 299bbb762db7 - stable/15 - nfs_clstate.c: Fix handling of delegation upgrades List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 299bbb762db7c6971ad68de412830dee8c0bae0a Auto-Submitted: auto-generated Date: Sat, 18 Jul 2026 01:16:54 +0000 Message-Id: <6a5ad406.440a0.1311ae8a@gitrepo.freebsd.org> The branch stable/15 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=299bbb762db7c6971ad68de412830dee8c0bae0a commit 299bbb762db7c6971ad68de412830dee8c0bae0a Author: Rick Macklem AuthorDate: 2026-07-04 22:00:02 +0000 Commit: Rick Macklem CommitDate: 2026-07-18 01:15:17 +0000 nfs_clstate.c: Fix handling of delegation upgrades Commit 016570c4463d modified the client to handle the upgrade of a read delegation to a write delegation, where the server provides the same delegation stateid to the client. However, it failed to check if the delegation structure was currently in use. Without this patch, if the structure was in use, a use after free could occur. This patch handles the "in use" case by copying the necessary fields into the current/old structure and free's the new one instead of the old one that is "in use". PR: 296224 (cherry picked from commit fe6677e7f440d1aa52de036639efc55047ab9a2b) --- sys/fs/nfs/nfsclstate.h | 6 ++++-- sys/fs/nfsclient/nfs_clstate.c | 45 +++++++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/sys/fs/nfs/nfsclstate.h b/sys/fs/nfs/nfsclstate.h index 92669ff8d1aa..714187e8a96b 100644 --- a/sys/fs/nfs/nfsclstate.h +++ b/sys/fs/nfs/nfsclstate.h @@ -162,17 +162,19 @@ struct nfscldeleg { struct nfsclownerhead nfsdl_owner; /* locally issued state */ struct nfscllockownerhead nfsdl_lock; nfsv4stateid_t nfsdl_stateid; - struct acl_entry nfsdl_ace; /* Delegation ace */ struct nfsclclient *nfsdl_clp; struct nfsv4lock nfsdl_rwlock; /* for active I/O ops */ +#define nfsdl_startcopy nfsdl_ace + struct acl_entry nfsdl_ace; /* Delegation ace */ struct nfscred nfsdl_cred; /* Cred. used for Open */ time_t nfsdl_timestamp; /* used for stale cleanup */ u_int64_t nfsdl_sizelimit; /* Limit for file growth */ u_int64_t nfsdl_size; /* saved copy of file size */ u_int64_t nfsdl_change; /* and change attribute */ struct timespec nfsdl_modtime; /* local modify time */ - u_int16_t nfsdl_fhlen; u_int8_t nfsdl_flags; +#define nfsdl_endcopy nfsdl_fhlen + u_int16_t nfsdl_fhlen; u_int8_t nfsdl_fh[1]; /* must be last */ }; diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 93e543197265..5c2d281cf35a 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -467,8 +467,11 @@ nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp, } else { /* * A delegation already exists. If the new one is a Write - * delegation and the old one a Read delegation, return the - * Read delegation. Otherwise, return the new delegation. + * delegation and the old one a Read delegation, upgrade + * if possible. The upgrade can be done if either: + * - The stateid is the same (true for the FreeBSD nfs server). + * - The current delegation is not locked. + * Otherwise, return the new delegation. */ if (dp != NULL) { if (NFSBCMP(dp->nfsdl_stateid.other, @@ -476,13 +479,37 @@ nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp, trydelegret = true; if ((dp->nfsdl_flags & NFSCLDL_WRITE) != 0 && (tdp->nfsdl_flags & NFSCLDL_READ) != 0) { - TAILQ_REMOVE(&clp->nfsc_deleg, tdp, nfsdl_list); - LIST_REMOVE(tdp, nfsdl_hash); - TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, - nfsdl_list); - LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, nfhp, - fhlen), dp, nfsdl_hash); - dp->nfsdl_timestamp = NFSD_MONOSEC + 120; + if (tdp->nfsdl_rwlock.nfslock_usecnt == 0 && + tdp->nfsdl_rwlock.nfslock_lock == 0) { + TAILQ_REMOVE(&clp->nfsc_deleg, tdp, + nfsdl_list); + LIST_REMOVE(tdp, nfsdl_hash); + TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, + nfsdl_list); + LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, + nfhp, fhlen), dp, nfsdl_hash); + dp->nfsdl_timestamp = NFSD_MONOSEC + + 120; + } else if (!trydelegret) { + /* + * For this case, the fields in + * struct nfscldeleg that change for a + * write delegation must be copied. + * This way, the delegation structure + * does not get free'd prematurely. + */ + memcpy(&tdp->nfsdl_startcopy, + &dp->nfsdl_startcopy, + __rangeof(struct nfscldeleg, + nfsdl_startcopy, nfsdl_endcopy)); + TAILQ_REMOVE(&clp->nfsc_deleg, tdp, + nfsdl_list); + TAILQ_INSERT_HEAD(&clp->nfsc_deleg, tdp, + nfsdl_list); + tdp->nfsdl_timestamp = NFSD_MONOSEC + + 120; + tdp = dp; /* Free the new one. */ + } } else { tdp = dp; /* Return this one. */ }