From nobody Sat Jul 4 22:01:30 2026 X-Original-To: dev-commits-src-main@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 4gt4Mb2Dqhz6kXdJ for ; Sat, 04 Jul 2026 22:01:31 +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 4gt4MZ4F27z3pjS for ; Sat, 04 Jul 2026 22:01:30 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783202490; 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=hxS7DOGCOal+Ae59r8OlEtZpfQqWPokUMNcagxv6tKE=; b=oglDZOasajSGZj+b7fzOWuiQTU7etGvHAeQgvkdYD+Jfz+ONm9Ab4R2djazEtluSQsGo3q UkMoo63Oy1RdOJcaaJIcy2D/a3wwcecHMYIgvAL/GXaJyD5kA1eu9gr8iC+Hq8xyHk4+YP V4GACYF+JEQYxtrWrP5wYBG8g1RsGsy9H3suWcLD2DoQzs4LX+MhxcXxyIMGBoQEHSpYRT mTLwNSHTNBykwQYyQ/ukbcb1c2KC8myDS9YsQ7XcCpaRczsIzg4I0xZjRp6UYNrGs3aTjl iw7PbzdGAfGZHJwGX976BvREC/+Qx4LB1dCQ+EXxfqG9SBIh9tUSQveB2sxJnQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1783202490; a=rsa-sha256; cv=none; b=Xjsf1z4mGL/0y55zKHU0vVMO4N7uUIJEbz8DZIaE66Ckwa/euvkzb2Ta0rOWsWFLHNk4lS IKD5O/abb+GtHsRLhK2Yi6bSsaYU5UsJN2kpQMSeMHII+zB3JlJ5qYfwZkpn3erXLyLfhl 6xKUyilNSXB7DAtwA7u2f6XvARiLUmg0O+Va4KfdzsjrfYCzMo6tLEvKoC8dOG1GFAH1NB 4Tmzu/GZTcNoZmZxSWDUQUh1ZOh9TIoHE9YV7NKh/ecdQGYlNaFhWOzGWVX/mJf9vj38lb EYaTvTqciw1k7s2vPYrVde4zAxlqZgOWtwkmZlRJOaj50LoOcUk+vt9xlw7vnA== 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=1783202490; 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=hxS7DOGCOal+Ae59r8OlEtZpfQqWPokUMNcagxv6tKE=; b=Ioten97Nl33EJAkypVPRgDFurUOBdtgQSSdaOErblRmj7cTadxtsJlgbuo/tkfun1DZ3a5 QB3RoDOKdg8iaioEpKYSbQ4IjAeUS31UhcRC+lN23bY9XCcT2kIJ9oJDfJOoaVtSbafuPx Fj6N895YtT3WiU/g8wy+yseb4Rp+k2ZT+kpHdhXYMcJraXEmoVeaDfTALlj+yMic6cA5rI IlxVwk6PkpxylV4jCx1xYXmHrvx6I2kdFGOscYxZD89NsSnPNFqP62IAaB04KOGWKDqx8L 8rnodWdF3FqFHqVyH5aqvwqs6oJY0+qI59wGMf9/LISQeke/dq6ZPSdXSfvnpw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gt4MZ39J6zqnY for ; Sat, 04 Jul 2026 22:01:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1dfc8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 04 Jul 2026 22:01:30 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: fe6677e7f440 - main - nfs_clstate.c: Fix handling of delegation upgrades List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@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/main X-Git-Reftype: branch X-Git-Commit: fe6677e7f440d1aa52de036639efc55047ab9a2b Auto-Submitted: auto-generated Date: Sat, 04 Jul 2026 22:01:30 +0000 Message-Id: <6a4982ba.1dfc8.46aecc98@gitrepo.freebsd.org> The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=fe6677e7f440d1aa52de036639efc55047ab9a2b commit fe6677e7f440d1aa52de036639efc55047ab9a2b Author: Rick Macklem AuthorDate: 2026-07-04 22:00:02 +0000 Commit: Rick Macklem CommitDate: 2026-07-04 22:00:02 +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 MFC after: 2 weeks --- 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 860a2bd1d4c3..ce8fc7018c4b 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 e906de603c28..aa3aef876cbe 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. */ }