From nobody Sat Jul 4 22:01:30 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 4gt4Mg6rPCz6kXsW for ; Sat, 04 Jul 2026 22:01:35 +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 4gt4Mg5lFvz3ppT for ; Sat, 04 Jul 2026 22:01:35 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783202495; 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=vClJn09fpWfcNX1s6MLxWjuFpaRQ4kPmrCY9//4mUR5M68BATlftpDMc+9VeBEDBl3AKMn CTdibHOQe4atRnAZN4isoUAolzhplNfudwuUTSGabgday9QuuJs0CVRyl4kbdvKhtYSj1c lfc6yLUfH4wB1RgJ3Zg8aOB3zlVydfKM4UCfU6bp1CUVC+MvXhPSEgcP+0O7KIQMcFfv32 S60gV1aHzIBoP4k3zwu44hQFS7drLURR4pm8zmu2yynM8uFhWn8N8tcJRZV2ndNR5B87iH xfD4WtR4L/3+HH1jgxDgD0BVfZ+cZ2hrcW/NdKtvr3RQy9TPHnkBeffchGoXeA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1783202495; a=rsa-sha256; cv=none; b=T0Sey4NEhb3Z2f7mJFEHhNM5+e54UW9n3C42u/1keso40CRaPEP9bqfQDYiWZOTpyIUg3u glUAeyRGxhh1s/Sh9xe0CPxBI+nP3IC7MmYgeuE/P8sYfEt/3QxUtDtQnoC2Zl4T0CdLOd UxOZO2WZxxwJJwGXvhz/rZi/mzz3H/KeF/4XyxyZ5uGwu81t3rOVeUQ6eaV4GXX2I36YsQ 10QZP99EwKxNWrG9V2Il5Z0NQNovF8tOYzBmA+HeifLHJODixwJ+qHeH1qS4WcbpWc076C YduoUJ5u3htGMhFCKgekU6blW4moolTnQV53u33OJnw69NMlzkbcHZojgij70g== 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=1783202495; 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=HEwBCfgpBxtqCTPKr37ymIZ2OrHNBFJ1RbYmdwmM6EUsBf9N3BOyVSI/Jsdo3RN7ul0+8D G3aXbBKTUpcemnaobSSxkK5KL63k6NU/pgVyBHfhoz1UViIRaAsjP9cClX/o+TyaxsLCMe 2llJYBZKPQZ0ro069Zaer66oh2Nrz51j0p16JiQ7LR5bccDo8209Xyr8KzBBNTZo/e7mjG oKzvPwfEShT1MAmnun9CR8gpA42qdbcdtxKvBxihCc44RHk7L02hI9A6jjtC+D0mOz26ic XIwc22PfUJi88ytjDAUMvXX+XLWR16TWZJtbopvZPsgawoRtvI7pzGbsQWASTA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gt4Mg3bBPzr9x for ; Sat, 04 Jul 2026 22:01:35 +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 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/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. */ }