From nobody Sat Jul 18 01:38:19 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 4h28Yl33xmz6lrc9 for ; Sat, 18 Jul 2026 01:38:19 +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 4h28Yl2KdFz3ZRV for ; Sat, 18 Jul 2026 01:38:19 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784338699; 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=Tc2omBbUcJFj1+lUGcCudkTHyc72bUCFe21pu+egDlQ=; b=k6mXSOU5AiGhJGRfmgWxEqFPGzRhMUgkFGKrSBWj3yReIVPcfIsuliBSeLkfnp8xjXxHv1 x83t8wEkIWuQaZX/+kZyOD8SliBgJV5r/vWwrhw9KTSoMA0PWsPVJ7tCGJD8AtBfJ7MUO5 oMlePMwiX7X2gc0nVQ9XN37BrO7FfdfM+o+wRT5m3dtiJl0vOcaCfIwFKQ01F2xCS3Fa88 UowasKENSHUkj2N1D+YYHhW8G2PV/Kfz9vTJb4sHELINCggXR564fer6rXHsd+k/kRiSSD YO4Zg3wGdQJu/dx7BUcykNaZkcJUkb9u/9VbjoNRCeTog4Ah4HDL97IEysek/g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784338699; a=rsa-sha256; cv=none; b=xGKmtzuObs0RgoHzpq1zV9UAQP7b0YlRv1OiePFbnWXoTgFQLPAjrbot1RVJcYl7BakHKd GC6MuFoT8jpRzGZS9JE6vsTRdTlVXzVhLve8kMqRQDaSCJP8ujJqCp2ArBztx3qyaU9fdh OwY0ETuiRp1YIHPDN0qcfMgeNVbuAR0/gWbU95Lb9ebDAcmn6RulZwPJfL1Apjs4TrpUW7 HAXRynXXEd51lUGZNny4yQ7a3+4VU5B/EtA5TlsdwInqlmTgLZYLHCZ2I5z12X40QFPTOW rVc/YhDW4yoLIHQcXAwcat/3gs4rae6lEAd5qX0wdYgJwTuV7lDlXvavLo86AA== 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=1784338699; 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=Tc2omBbUcJFj1+lUGcCudkTHyc72bUCFe21pu+egDlQ=; b=b23V4lldCBxigR2Ki75Q7UrMIPre6xAVLtiKn9zD31pRwFVinAtEgV7vqJ2yaKjofYd+Cw yzuy4fz29qbOlhOgYJJs2NpyyyrIZnUB5O++CeocCalWWnuQXs03KE1psqC9LiuENr85YC f6Is40aRd+Wit2f4KrOcwtDzJ3wlexUjWbG4amX88z0XDtVQI0H2gjgaTcQyIW2OnNPEhr dn0l2l0IBOTdkjO+Jxstr8EOfQaa8yi2MNo1bJ54wxx7QwEAX8PrIn4lJ32lhKB6c0v7Lr 7craHbC+akf7u/vBT3oXSxQAsp9877yC8ZaLZM1vhPshClb03BQhbrXM1AKUBw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h28Yl17V6z1C0R for ; Sat, 18 Jul 2026 01:38:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 46896 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 18 Jul 2026 01:38:19 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: a51fdce1b28a - stable/14 - 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/14 X-Git-Reftype: branch X-Git-Commit: a51fdce1b28aba5e857f0d4a27d2e2e59dd0ef7e Auto-Submitted: auto-generated Date: Sat, 18 Jul 2026 01:38:19 +0000 Message-Id: <6a5ad90b.46896.208522f7@gitrepo.freebsd.org> The branch stable/14 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=a51fdce1b28aba5e857f0d4a27d2e2e59dd0ef7e commit a51fdce1b28aba5e857f0d4a27d2e2e59dd0ef7e Author: Rick Macklem AuthorDate: 2026-07-04 22:00:02 +0000 Commit: Rick Macklem CommitDate: 2026-07-18 01:36:06 +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 624b782baf6e..602f2d70ed8b 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -466,8 +466,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, @@ -475,14 +478,38 @@ 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); *dpp = NULL; - 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 { *dpp = NULL; tdp = dp; /* Return this one. */