From nobody Tue Apr 29 23:26:33 2025 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 4ZnGff0lRFz5vhbn; Tue, 29 Apr 2025 23:26:34 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZnGfd5WSyz3rlT; Tue, 29 Apr 2025 23:26:33 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1745969193; 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=ny4bolHRcbAbblUX/PLKzpqjjjTIrLAmq/j7Zu9krno=; b=jfxYeHuu0MgpLDjtFzeTXu30AsY80mH9hlrap2piQvtVujrPzvu7xnB1IBMcHaIK5sFMQB Jd5QAihKcZuzsk9N3uOKXleDCvtvlU6fMKvQRKrwx1AOd94uyj3rVK7u3SZa5pwtKdZLvz 2VQUfJx/KA/h+AXfktZzsxbVCqWJohCkigsH1pydlfR3KTUYH5y4cyelnwSYp7q1070c// 88kXrzIPOlVq0RnPvsNQCyo9ZEfr38nUK8Ix37/g2td+o0kogx/JtgfT2rhwYnmsWSzbTG M640yQOdhL8u8EDaBD3pNDMa03Q/2nZXYfKSiAzISo5ygZkw27ooB+UCMC+ENg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1745969193; a=rsa-sha256; cv=none; b=re1SgGE3RNm+a5w7ZuJze4tHTqq0v7g3AzctsTxaOe/VaX4zDthXmJlW8kRuGLAtzEY2YI Dm7UYgA+vojX0QerUbDY+cd7lnxUM5FnvQhLPdtNKgWQWp61qo0R8J50wn1So3YGjfzfY4 BoFyDRK7QMull+FyKSHxi1J6HXWu/nRZ5bx/dz4v0UDbSG2+7mKJApy1bd1BmtHk1RbpAS Vw3FctxhxceiGewAPTtUGO+U9/mTPUjJYThxOV7RrVvZiAbPhFEx4UseU7WQGRgmrpIBHg P0KwwqDAc2TuH8vwgYCWmYcc4fprpbwd93XcLdh/BalP7i1Kmd4eB+d4jzZucQ== 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=1745969193; 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=ny4bolHRcbAbblUX/PLKzpqjjjTIrLAmq/j7Zu9krno=; b=wWy4i2XXr/RITk3R+1CnDPZQ+zetNHVzS6TYX92xM7KoYF+tC5ShxesG+0Kk/eUmae2bIu ZjYKGf4LxkPPt+ZEh4gcjh4diLW85xdJPWB/comN5mwcZuAFi6mzHwTemiKtE4GcWtlxkF CSVCGev/J4SPjG2XNTmLWkDuqih3P8fwtIxYOuQOqp9Ualf59+trIpHz1J2jowcdSY4s11 bJP00Ul9fyXFDqK/OoEGMP4xFa1jOLqnkdpP8z2yr3Cl1glFeaokd0WrMePl7AGbmqr5Qy nbWh7r5PClgLQwD1uWZ685f2wFQh05wppkFeYD8dhu4ylEXo+DdVo63cy8XWvA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ZnGfd4fFSzhp2; Tue, 29 Apr 2025 23:26:33 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 53TNQXws075608; Tue, 29 Apr 2025 23:26:33 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 53TNQXqW075605; Tue, 29 Apr 2025 23:26:33 GMT (envelope-from git) Date: Tue, 29 Apr 2025 23:26:33 GMT Message-Id: <202504292326.53TNQXqW075605@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alan Somers Subject: git: d5e3cf41e894 - main - fusefs: Upgrade FUSE protocol to version 7.33. 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 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: d5e3cf41e89400e75da87aad0cc9bde108e2573b Auto-Submitted: auto-generated The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=d5e3cf41e89400e75da87aad0cc9bde108e2573b commit d5e3cf41e89400e75da87aad0cc9bde108e2573b Author: Claudiu I. Palincas AuthorDate: 2025-02-03 15:50:09 +0000 Commit: Alan Somers CommitDate: 2025-04-29 22:03:32 +0000 fusefs: Upgrade FUSE protocol to version 7.33. This commit upgrades the FUSE API to protocol 7.33, it doesn't implement any of protocol 7.33's new features, setxattr is tested for binary compatibility with protocol version 7.32. Update sys/fs/fuse/fuse_vnops.c Reviewed by: Alan Somers Pull Request: https://github.com/freebsd/freebsd-src/pull/1681 --- sys/fs/fuse/fuse_kernel.h | 47 ++++++++++++++++++++++++++++++++++++------- sys/fs/fuse/fuse_vnops.c | 16 ++++++++++++--- tests/sys/fs/fusefs/xattr.cc | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/sys/fs/fuse/fuse_kernel.h b/sys/fs/fuse/fuse_kernel.h index 14d5508ba3fa..c95caf898ad8 100644 --- a/sys/fs/fuse/fuse_kernel.h +++ b/sys/fs/fuse/fuse_kernel.h @@ -176,6 +176,12 @@ * * 7.32 * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS + * + * 7.33 + * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID + * - add FUSE_OPEN_KILL_SUIDGID + * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT + * - add FUSE_SETXATTR_ACL_KILL_SGID */ #ifndef _FUSE_FUSE_KERNEL_H @@ -211,7 +217,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 32 +#define FUSE_KERNEL_MINOR_VERSION 33 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -272,6 +278,7 @@ struct fuse_file_lock { #define FATTR_MTIME_NOW (1 << 8) #define FATTR_LOCKOWNER (1 << 9) #define FATTR_CTIME (1 << 10) +#define FATTR_KILL_SUIDGID (1 << 11) /** * Flags returned by the OPEN request @@ -321,6 +328,12 @@ struct fuse_file_lock { * foffset and moffset fields in struct * fuse_setupmapping_out and fuse_removemapping_one. * FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts + * FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc. + * Upon write/truncate suid/sgid is only killed if caller + * does not have CAP_FSETID. Additionally upon + * write/truncate sgid is killed only if file has group + * execute permission. (Same as Linux VFS behavior). + * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -350,6 +363,8 @@ struct fuse_file_lock { #define FUSE_EXPLICIT_INVAL_DATA (1 << 25) #define FUSE_MAP_ALIGNMENT (1 << 26) #define FUSE_SUBMOUNTS (1 << 27) +#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) +#define FUSE_SETXATTR_EXT (1 << 29) #ifdef linux /** @@ -381,11 +396,14 @@ struct fuse_file_lock { * * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed * FUSE_WRITE_LOCKOWNER: lock_owner field is valid - * FUSE_WRITE_KILL_PRIV: kill suid and sgid bits + * FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits */ #define FUSE_WRITE_CACHE (1 << 0) #define FUSE_WRITE_LOCKOWNER (1 << 1) -#define FUSE_WRITE_KILL_PRIV (1 << 2) +#define FUSE_WRITE_KILL_SUIDGID (1 << 2) + +/* Obsolete alias; this flag implies killing suid/sgid only. */ +#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID /** * Read flags @@ -440,6 +458,18 @@ struct fuse_file_lock { */ #define FUSE_ATTR_SUBMOUNT (1 << 0) +/** + * Open flags + * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable + */ +#define FUSE_OPEN_KILL_SUIDGID (1 << 0) + +/** + * setxattr flags + * FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set + */ +#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ @@ -602,14 +632,14 @@ struct fuse_setattr_in { struct fuse_open_in { uint32_t flags; - uint32_t unused; + uint32_t open_flags; /* FUSE_OPEN_... */ }; struct fuse_create_in { uint32_t flags; uint32_t mode; uint32_t umask; - uint32_t padding; + uint32_t open_flags; /* FUSE_OPEN_... */ }; struct fuse_open_out { @@ -671,9 +701,13 @@ struct fuse_fsync_in { uint32_t padding; }; +#define FUSE_COMPAT_SETXATTR_IN_SIZE 8 + struct fuse_setxattr_in { uint32_t size; uint32_t flags; + uint32_t setxattr_flags; + uint32_t padding; }; struct fuse_listxattr_in { @@ -928,7 +962,6 @@ struct fuse_copy_file_range_in { uint64_t flags; }; - #define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0) #define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1) struct fuse_setupmapping_in { @@ -957,6 +990,6 @@ struct fuse_removemapping_one { }; #define FUSE_REMOVEMAPPING_MAX_ENTRY \ - (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) + (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) #endif /* _FUSE_FUSE_KERNEL_H */ diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 9c858d6c467d..016b634c4fa0 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -2704,6 +2704,7 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap) struct mount *mp = vnode_mount(vp); struct thread *td = ap->a_td; struct ucred *cred = ap->a_cred; + size_t struct_size = FUSE_COMPAT_SETXATTR_IN_SIZE; char *prefix; size_t len; char *attr_str; @@ -2744,17 +2745,26 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap) len = strlen(prefix) + sizeof(extattr_namespace_separator) + strlen(ap->a_name) + 1; - fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid); + /* older FUSE servers use a smaller fuse_setxattr_in struct*/ + if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) + struct_size = sizeof(*set_xattr_in); + + fdisp_init(&fdi, len + struct_size + uio->uio_resid); fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred); set_xattr_in = fdi.indata; set_xattr_in->size = uio->uio_resid; - attr_str = (char *)fdi.indata + sizeof(*set_xattr_in); + if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) { + set_xattr_in->setxattr_flags = 0; + set_xattr_in->padding = 0; + } + + attr_str = (char *)fdi.indata + struct_size; snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator, ap->a_name); - err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len, + err = uiomove((char *)fdi.indata + struct_size + len, uio->uio_resid, uio); if (err != 0) { goto out; diff --git a/tests/sys/fs/fusefs/xattr.cc b/tests/sys/fs/fusefs/xattr.cc index 0cd2783551b4..0ab203c96254 100644 --- a/tests/sys/fs/fusefs/xattr.cc +++ b/tests/sys/fs/fusefs/xattr.cc @@ -110,6 +110,8 @@ void expect_setxattr(uint64_t ino, const char *attr, const char *value, const char *v = a + strlen(a) + 1; return (in.header.opcode == FUSE_SETXATTR && in.header.nodeid == ino && + in.body.setxattr.size == (strlen(value) + 1) && + in.body.setxattr.setxattr_flags == 0 && 0 == strcmp(attr, a) && 0 == strcmp(value, v)); }, Eq(true)), @@ -119,6 +121,33 @@ void expect_setxattr(uint64_t ino, const char *attr, const char *value, }; +class Xattr_7_32:public FuseTest { +public: +virtual void SetUp() +{ + m_kernel_minor_version = 32; + FuseTest::SetUp(); +} + +void expect_setxattr_7_32(uint64_t ino, const char *attr, const char *value, + ProcessMockerT r) +{ + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + const char *a = (const char *)in.body.bytes + + FUSE_COMPAT_SETXATTR_IN_SIZE; + const char *v = a + strlen(a) + 1; + return (in.header.opcode == FUSE_SETXATTR && + in.header.nodeid == ino && + in.body.setxattr.size == (strlen(value) + 1) && + 0 == strcmp(attr, a) && + 0 == strcmp(value, v)); + }, Eq(true)), + _) + ).WillOnce(Invoke(r)); +} +}; + class Getxattr: public Xattr {}; class Listxattr: public Xattr {}; @@ -153,6 +182,7 @@ void TearDown() { class Removexattr: public Xattr {}; class Setxattr: public Xattr {}; +class Setxattr_7_32:public Xattr_7_32 {}; class RofsXattr: public Xattr { public: virtual void SetUp() { @@ -728,6 +758,7 @@ TEST_F(Removexattr, system) << strerror(errno); } + /* * If the filesystem returns ENOSYS, then it will be treated as a permanent * failure and all future VOP_SETEXTATTR calls will fail with EOPNOTSUPP @@ -815,6 +846,23 @@ TEST_F(Setxattr, system) ASSERT_EQ(value_len, r) << strerror(errno); } + +TEST_F(Setxattr_7_32, ok) +{ + uint64_t ino = 42; + const char value[] = "whatever"; + ssize_t value_len = strlen(value) + 1; + int ns = EXTATTR_NAMESPACE_USER; + ssize_t r; + + expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); + expect_setxattr_7_32(ino, "user.foo", value, ReturnErrno(0)); + + r = extattr_set_file(FULLPATH, ns, "foo", (const void *)value, + value_len); + ASSERT_EQ(value_len, r) << strerror(errno); +} + TEST_F(RofsXattr, deleteextattr_erofs) { uint64_t ino = 42;