Page MenuHomeFreeBSD

D48818.diff
No OneTemporary

D48818.diff

diff --git a/sys/fs/fuse/fuse_kernel.h b/sys/fs/fuse/fuse_kernel.h
--- 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 @@
#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 @@
* 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 @@
#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 @@
*
* 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
@@ -435,11 +453,22 @@
/**
* fuse_attr flags
- *
* FUSE_ATTR_SUBMOUNT: Object is a submount root
*/
#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 */
@@ -494,7 +523,7 @@
CUSE_INIT = 4096,
/* Reserved opcodes: helpful to detect structure endian-ness */
CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */
- FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */
+ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */
#endif /* linux */
};
@@ -602,14 +631,14 @@
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 +700,13 @@
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 +961,6 @@
uint64_t flags;
};
-
#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0)
#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1)
struct fuse_setupmapping_in {
@@ -957,6 +989,6 @@
};
#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
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2704,6 +2704,7 @@
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 @@
len = strlen(prefix) + sizeof(extattr_namespace_separator) +
strlen(ap->a_name) + 1;
- fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
+ /* we want to be binary compatible */
+ 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
--- a/tests/sys/fs/fusefs/xattr.cc
+++ b/tests/sys/fs/fusefs/xattr.cc
@@ -110,6 +110,8 @@
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.flags == 0 &&
0 == strcmp(attr, a) &&
0 == strcmp(value, v));
}, Eq(true)),
@@ -119,6 +121,33 @@
};
+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) &&
+ in.body.setxattr.flags == 0 &&
+ 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 @@
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 @@
<< 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 @@
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;

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 10, 5:29 PM (7 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16553260
Default Alt Text
D48818.diff (7 KB)

Event Timeline