From nobody Sun Jun 14 17:55:39 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 4gdgsF2Cq7z6h7w0 for ; Sun, 14 Jun 2026 17:55:45 +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 "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gdgsF1bgNz46vj for ; Sun, 14 Jun 2026 17:55:45 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781459745; 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=zZboxh4UmIwODhcMJyBFbuM5L9UUUwlMUUAUxczl7Nk=; b=YquWOC25Kq2dkhZgLYLC7tEwj6I81t75clxinh+kZgq7zFDANWQF5vWtva8PKDZvCCcp9D fSHzCLWoFs0MygOc73JeETv6ayWnGkG9TbWP9vvQwuXCfzCQEgMHTHiW6s8cwNHY+Xozm9 5KkOHzSinvxSn+u89ib/+PMeEgsF21z4Qi+XJAVhnfaNz1urpFyohyYGq2xRyFSRMDh2YX X8HNa+Ope2jHU/jwEB1goKecWpmCj9Sk0aauG0a3JVLEBpU1YUZyhd0q3DOZ3bA3uRRqgs A7PYLNyIVBvi4B+OGI8hLWlsVV6An+CKsaqS+D4Na+CQ8A4QZSRZa6ZVu+P5Ow== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1781459745; a=rsa-sha256; cv=none; b=eMql0lPon/PFcVzxQ9lEm0LOCmJj4+Wdc2qhT8vASMl8d0LYRkAGMKwiXR3uNNg2b1fT/Q CjD9gkIyClkVIZyF4kpENN45xMG8Z9AAq+Ob4GuCgBvOn8o0sYzZM7jhPW8qHp0CRBxkzQ CeDwwl/C8cO3Z5BZe7gbXKh/llCqbqydsn9lVEhPVP8XPIkYwAOQjJfq5uh/LH2ZpRTkDd yemaYEgo+l9bUj4Fv2FgYgm/xDtLQZsfJMPPDA+DTH85UwthQyBabNFosc5JeB8GrsVbv8 4g/8maot6F7Fn9lifoolcv9qRmUQ6DXzPEd+YoesR60PNAFzF+XS/mg+7vRYoA== 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=1781459745; 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=zZboxh4UmIwODhcMJyBFbuM5L9UUUwlMUUAUxczl7Nk=; b=oYRwgEvKkdsartZCan0kyIRczBRvo8LkrBK80V97QP/hg2lAOTJzMBaN1WyddRS1pXvOmA +v6yTywki9NkDhCXFmk9/GiXNW0fWosGz46MGgdE2/JqqPev7VJKlbJFBFZrX5phrbsW7o ppJccl3Lu4EyJV46vVc4P/wK+k4Tvypq/cXoz0HniIIv4dXXTuO05O1hkS2dh8sP7at2i/ S5ZI/49KlsTTNiJDw9VnbT7Y2tIVH+mFy33i2XfL8Tb/aqTnsjrRWRap+65BOt02I2Xop3 QFx1FCVR/vLbRX+DwFmpEPfbxuvADjXk/2povj/VMdwruPrX6mkqfVw4E+3qbw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gdgsF19nKz43S for ; Sun, 14 Jun 2026 17:55:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1c54e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 14 Jun 2026 17:55:39 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alan Somers Subject: git: b4af6a4cccc3 - main - 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/main X-Git-Reftype: branch X-Git-Commit: b4af6a4cccc3b4b0ea461463196c258eb92ad2e5 Auto-Submitted: auto-generated Date: Sun, 14 Jun 2026 17:55:39 +0000 Message-Id: <6a2eeb1b.1c54e.1571e168@gitrepo.freebsd.org> The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=b4af6a4cccc3b4b0ea461463196c258eb92ad2e5 commit b4af6a4cccc3b4b0ea461463196c258eb92ad2e5 Author: Alan Somers AuthorDate: 2026-06-14 17:37:15 +0000 Commit: Alan Somers CommitDate: 2026-06-14 17:55:22 +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 MFC after: 2 weeks Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D57588 --- 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 242e023a38dd..f5c832cbbd13 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1743,14 +1743,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) {