From nobody Wed Jul 8 17:57:32 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 4gwQmF16xpz6kcBY for ; Wed, 08 Jul 2026 17:57:33 +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 4gwQmF0K2jz47sJ for ; Wed, 08 Jul 2026 17:57:33 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783533453; 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=PUBmNWLv2z4NKKsPXdws4QqgUmLH1jPNqYKvKhL7GRY=; b=gfC/XzMJKUYK1kUIOYVxj/TDaY7+EqjMxsK7IRVm+hgmYcPPlxp3oEQ45nxM7mWItUrrFR i6UuTxZ0aTC9TQFqnhooOKCbZSUsIlylpyv3sf0i2gDkQL7RiZSLO0CBUuynITJxEAOQhE K/QH6j6oGtW0mIlQTBKz/ZwGtD/tgevGh4oh3yHP68CJ9f8bHJ90B6QYVAeuoVQqE9mW3x iUcQKMKaDe0AUz5APf7NBUNThDqkbcqLPw7pH1vS3EFuhyEBrJZOlTOP/u0byIUobm1WFP A4GACnPE3zi6d6f4ol5csApaZq9U/0r/pnHCpvVpOpEYbmOT01LuYhmf1PAXVg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1783533453; a=rsa-sha256; cv=none; b=O9QhsUUmdQm4rnJ/Ocdlo3spWeO+oVwfYkHlfXYOTxQKq+9yJA1Tz78tpuNfADnGPkpPz2 1GXtHAIn283EqyfE8B7374OFjc6yi8CC32e0CSPWXd2ZdvhC0iyyKjKHmWReqKWNGbgM4m /ike8s097YrJUNhusHqjdh4wK3A9UbAdsXiGai+0Xm7USrvMT415T5alayY1Gw4IRLtHkX CVguJU4ZfkcvG7TBeEgGayeKx0J2RWz/TaJFZJUD4T7wJuPweAutXAMdMut/lviqPcyZpr XKSrZCMfqa9eB+maDYDCAU1P86kpmpu9/sA9t5/Y+CAT18NPAMy91e2pRP/XqQ== 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=1783533453; 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=PUBmNWLv2z4NKKsPXdws4QqgUmLH1jPNqYKvKhL7GRY=; b=xG6DPUHiS5KvgY88iTHYMlC2MHNv5QuSX2iseHUxLJ7BtGW7bOR5J+2jlp4DDQJnFKyvFF sqJJVwNqj/1J/fJEsLuUruo5G/jaFmDYIznJ9ULIUzA7Z6JlCgJBi++L0NYxzLzeEQjcnm euv4/vtIrzhgoqFH4SJk5/LVXihWzt9F6M5Yin0bZc2IjmnKxzPd3bBnjGgvcUQksDNKia ZexZwotMjIo3FsawIy+fprBfcVSzwgqj6qXh2YtU33vyCVEnWNrHBRQedZA80/EGyv1GcI AMuGoEn/P9i00y0Ok46B7/yEeL8rC1N87u5EkKsxKYFp35hL15aaPq3FoQgZgA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gwQmD6CdyzYjw for ; Wed, 08 Jul 2026 17:57:32 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 38d08 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 08 Jul 2026 17:57:32 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Alan Somers Subject: git: 2da045abb9f0 - stable/15 - fusefs: fix error handling when reading a directory's sticky bit 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: asomers X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 2da045abb9f0e36531910f5c80c7293be1d0771c Auto-Submitted: auto-generated Date: Wed, 08 Jul 2026 17:57:32 +0000 Message-Id: <6a4e8f8c.38d08.163c098e@gitrepo.freebsd.org> The branch stable/15 has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=2da045abb9f0e36531910f5c80c7293be1d0771c commit 2da045abb9f0e36531910f5c80c7293be1d0771c Author: Alan Somers AuthorDate: 2026-06-14 17:37:15 +0000 Commit: Alan Somers CommitDate: 2026-07-08 17:56: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 d5404a8b9805..b5f65decc399 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1660,14 +1660,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) {