From nobody Wed Aug 5 03:26:42 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 4hFG6V59Qkz6JVBb for ; Wed, 05 Aug 2026 03:26:42 +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 4hFG6V4WBmz3Kxc for ; Wed, 05 Aug 2026 03:26:42 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785900402; 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=f80jhdJgVsql7UmvvrmuKEhk6FwasilIwJcQep1gHc4=; b=U4nKWzInbFdStiRwgtatafuekQLEs1zU43WNnJlHAPm1xW/MJy2icDCiSUIEvQcjfmKEIh Sc+pKAzdim1QiJI37YQjezj2EUSgwfhK7QXc48ACyR4ZZG2wkgeHhRhaoglVdxsBXOBmBJ wvGT2zHjErJUzsAnyeUbdhVnbXTtS0YkIZIqeJUeFFBR8V0++MtcSvV2LeQ8QQnrW9PfD+ rMW6uBpZVbUZzb3NOGm4WKhmCP3a3zt0p2Qbp5bZrjSPN3Neo/hpFbZ0wVuZpLqNzMAj6P pOVYowHZpT7s5wRjJM8P5uIEFiuzl1Gp0lGz9B8EarrikR0kjAOoocMYeGB6uA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785900402; a=rsa-sha256; cv=none; b=ZE1Jd4G4y4LHU4XhDT2APW/bGDIYdgHY0FhtFJTa1QpqiRty3YjSnVzR9DfCQTjWQpx9Ds sIgGKKRmtyzAyK2w4yjNrqhBZ87P7kFc8B+5esth7ka4XIz+C0Y1s5e63zzY5R/LuI2qhY cnIikeXFgcnd2sI1IyquiWNzGIfc48GJ5Ba71os1iQuMVZj6/VwYjEIFtRlThRHH6kkG69 NvoKAxGOJHC1RaqilDMCkhzaAnkuW0iHMfgJB+5m3YNMuh33KXejXPF6aa1SsN/qMoW+uC 83JrBgy8jxpDVgvK91zwOJvRey6XZQd77B5h1d6aDccuPzFS8DlqMXzrlcAvWA== 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=1785900402; 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=f80jhdJgVsql7UmvvrmuKEhk6FwasilIwJcQep1gHc4=; b=CGkw39I7RXCngTqNAluOheFjuK9mfMp/GhW+fCqAqFZYlBgJ/x1Fg568r8KnDjEsq23JBa zXbFvF3SrHBWnBk39FYfdxCHz0Jn99dQ9/jNObf2gLFIxtjrPs9BlqgP6TdlSWUn8rujV1 BbKUgWrxkn2fUDVI1LNXvAYW9K+vyauiACTEEHOl16uuMIcjk/cfND1+ZIa9Y9CP7K9Y8e XMkTDIL8GP8r9ZVAJdfaFh8FDTnQJGM6RLZ2iuiSEEHBKOJ4NC6RYRyH+GS5LFI2fYTFA3 UGB3SUTh9TblviIXWujSYz07X1bUgN2l/iQIE5Xd6vLb86ohXAG+B5Zp4yMtcQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hFG6V3NnNz1Wb for ; Wed, 05 Aug 2026 03:26:42 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 41b6e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 05 Aug 2026 03:26:42 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Alan Somers Subject: git: bdf902719e33 - stable/14 - fusefs: fix error handling when reading a directory's sticky bit 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: asomers X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: bdf902719e33d3dbcb91f95619e9b2d7d6a14dd4 Auto-Submitted: auto-generated Date: Wed, 05 Aug 2026 03:26:42 +0000 Message-Id: <6a72ad72.41b6e.5005ce1@gitrepo.freebsd.org> The branch stable/14 has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=bdf902719e33d3dbcb91f95619e9b2d7d6a14dd4 commit bdf902719e33d3dbcb91f95619e9b2d7d6a14dd4 Author: Alan Somers AuthorDate: 2026-06-14 17:37:15 +0000 Commit: Alan Somers CommitDate: 2026-08-05 03:21:50 +0000 fusefs: fix error handling when reading a directory's sticky bit When trying to delete or rename a file, fuse_vnop_lookup must check whether its parent directory's sticky bit is set. Realistically, the parent directory's attributes will almost always be cached. But it's possible that they won't be, and in that case we must send a new FUSE_GETATTR request to the server. If that request fails for some reason, then we must fail the lookup. Prior to this change fusefs would ignore failure of that request. Reported by: Yuxiang Yang, Yizhou Zhao, Ao Wang, Xuewei Feng, Qi Li, and Ke Xu of Tsinghua University Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D57588 (cherry picked from commit b4af6a4cccc3b4b0ea461463196c258eb92ad2e5) --- sys/fs/fuse/fuse_vnops.c | 10 +++--- tests/sys/fs/fusefs/default_permissions.cc | 53 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 5ebdc17048a0..adc5b0b92ec7 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1631,14 +1631,16 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) * Need to figure out the vnode locking to make * this work. */ - fuse_internal_getattr(dvp, &dvattr, cred, td); - if ((dvattr.va_mode & S_ISTXT) && + err = fuse_internal_getattr(dvp, &dvattr, cred, + td); + if (err == 0 && + (dvattr.va_mode & S_ISTXT) && fuse_internal_access(dvp, VADMIN, td, cred) && fuse_internal_access(*vpp, VADMIN, td, - cred)) { + cred)) + { err = EPERM; - goto out; } } } diff --git a/tests/sys/fs/fusefs/default_permissions.cc b/tests/sys/fs/fusefs/default_permissions.cc index 4b04297d97ac..f9a37f904d30 100644 --- a/tests/sys/fs/fusefs/default_permissions.cc +++ b/tests/sys/fs/fusefs/default_permissions.cc @@ -1562,6 +1562,59 @@ TEST_F(Unlink, sticky_directory) ASSERT_EQ(EPERM, errno); } +/* + * When trying to delete or rename a file, we must check its parent directory's + * sticky bit. That may entail a FUSE_GETATTR. If that operation fails, then + * we must fail the rename or delete. + */ +TEST_F(Unlink, sticky_directory_io_during_getattr) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + Sequence seq; + uint64_t ino = 42; + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in.header.opcode == FUSE_GETATTR && + in.header.nodeid == FUSE_ROOT_ID); + }, Eq(true)), + _) + ).Times(2) + .InSequence(seq) + .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { + SET_OUT_HEADER_LEN(out, attr); + out.body.attr.attr.ino = FUSE_ROOT_ID; + out.body.attr.attr.mode = S_IFDIR | 0177; + /* + * Realistically, the parent directory's attributes will almost + * always be cached when we try to lookup the sticky bit. For + * this test case, set attr_valid to 0 so that won't be the + * case. + */ + out.body.attr.attr_valid = 0; + }))); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in.header.opcode == FUSE_GETATTR && + in.header.nodeid == FUSE_ROOT_ID); + }, Eq(true)), + _) + ).Times(1) + .InSequence(seq) + .WillOnce(Invoke(ReturnErrno(EIO))); + expect_lookup(RELPATH, ino, S_IFREG | 0644, UINT64_MAX, 0); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in.header.opcode == FUSE_UNLINK); + }, Eq(true)), + _) + ).Times(0); + + ASSERT_EQ(-1, unlink(FULLPATH)); + ASSERT_EQ(EIO, errno); +} + /* A write by a non-owner should clear a file's SUID bit */ TEST_F(Write, clear_suid) {