From nobody Sat Jul 18 01:38:19 2026 X-Original-To: dev-commits-src-all@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 4h28Yr4QPYz6lrqh for ; Sat, 18 Jul 2026 01:38:24 +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 4h28Yr37lcz3ZTw for ; Sat, 18 Jul 2026 01:38:24 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784338704; 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=aXTpK7+Z3axPNPkgOFq4q3MM3ZEe5kjVS7ZmudzfmgeNN/7Kzoc6hw94gBm9jaUIDCMZf1 V1Kg4TocSN09OMNlmEQwnVtHzdS1tta8a9VKXyihYzmAEE4ltQCF5+LTcwnTXaeRkbPcV0 APadCHzntc3KQEMJVT18yDV0c7sT5VAjsNfa//B66HZYNSi9cfJvD7I5CJytSDyfQSqJpa VYTdhHCclGg2AfXeaVXXwtTOLWhLq9v7mLUcbQ3sh+JjuMSd9gpxdHqVtdIxr+cDhmiR9L jNyYZELMTEVlEVEmwhqv4g0soLXY7rr9KO/hs0CsALn3YCERekqYbiCFFSmH8Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784338704; a=rsa-sha256; cv=none; b=Urk5opR1gJ8CHH7IyZOS9mcYBM1TYuajPnGlUd3okaupfe8UZ9folwMtwEEtdGjGojhJWz TAHYn0AGcerrEtlzMoa6RhqLGPs8exV0iJee5n75S0N29UmOC44AKFS0tza3RAyNb6PDvr 12p+qXH3lBMxrBf9BdZLrm4Udi3q2Xq1UGLXwiKi5hefWiediEAn6EcS2QrJfwaM6CcFIO h4MI5UwMaZw5EZBw3S931gAX5bdCp8hkYchllVYUosDjZKYMMB2N6H3THUE0brSlscV/Y7 n8vS7bMg7Vn5IQ0AygA853ndxx+RNS5GOsWWmy337+DgaQiINXLKC8sXRFNGPQ== 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=1784338704; 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=PgMTFyH905DHyzwlGULWykVWhBFajoWJBSJgT81HjuPqLJz0q81QP4Z89RY1mVNyov6hpC KY3hnRdiOHIrHXZTeTJjo+Er0bbO6tmtdIYDVx+g+Ssf3LfhMspK28qQ036XsWwdquOGmo fIgs87lzuDQQbHUFl8+pJC6AX6XFTIhUrQz1dJ/wMQNoBw73eubrrtC54sRl0tegd1HPXe PTIFYNi1A0qGXdMsufEYZoWETYMYRonx4knGJS3O4HfYq6G5MmjdTk16lH7NiO3uvo+NJg JWwYJARJCkpITcVvCPCIaXwgTiHUUof3ojyQh08VeYY4GIh591rVUSULlVBB/w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h28Yr26nYz1BjY for ; Sat, 18 Jul 2026 01:38:24 +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: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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. */