From 05de3c98c07e636e007e7ecf6516508426d02c83 Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Tue, 22 Nov 2016 15:56:55 -0800 Subject: [PATCH] Add support for FUSE_HANDLE_KILLPRIV Fixes #116. --- ChangeLog.rst | 7 ++++++- include/fuse.h | 12 ++++++++++++ include/fuse_common.h | 9 +++++++++ include/fuse_lowlevel.h | 10 ++++++++++ lib/fuse_lowlevel.c | 3 +++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index 9c1a5dd..999f431 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -22,8 +22,13 @@ UNRELEASED CHANGES particular capability can still be disabled by unsetting the corresponding bit of `fuse_conn_info.wants` in the init() handler. -* Added FUSE_CAP_PARALLEL_DIROPS and FUSE_CAP_POSIX_ACL feature flags. +* Added FUSE_CAP_PARALLEL_DIROPS and FUSE_CAP_POSIX_ACL, + FUSE_HANDLE_KILLPRIV feature flags. +* FUSE filesystems are now responsible for unsetting the setuid/setgid + flags when a file is written, truncated, or its owner + changed. Previously, this was handled by the kernel but subject to + race conditions. FUSE 3.0.0-rc2 (2016-11-06) =========================== diff --git a/include/fuse.h b/include/fuse.h index 60015ca..56539f1 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -351,6 +351,9 @@ struct fuse_operations { * * `fi` will always be NULL if the file is not currenly open, but * may also be NULL if the file is open. + * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. */ int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi); @@ -358,6 +361,9 @@ struct fuse_operations { * * `fi` will always be NULL if the file is not currenly open, but * may also be NULL if the file is open. + * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. */ int (*truncate) (const char *, off_t, struct fuse_file_info *fi); @@ -395,6 +401,9 @@ struct fuse_operations { * Write should return exactly the number of bytes requested * except on error. An exception to this is when the 'direct_io' * mount option is specified (see read operation). + * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. */ int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); @@ -635,6 +644,9 @@ struct fuse_operations { * Similar to the write() method, but data is supplied in a * generic buffer. Use fuse_buf_copy() to transfer data to * the destination. + * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. */ int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); diff --git a/include/fuse_common.h b/include/fuse_common.h index f336129..04b378f 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -267,6 +267,15 @@ struct fuse_file_info { */ #define FUSE_CAP_POSIX_ACL (1 << 19) +/** + * Indicates that the filesystem is responsible for unsetting + * setuid and setgid bits when a file is written, truncated, or + * its owner is changed. + * + * This feature is enabled by default when supported by the kernel. + */ +#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20) + /** * Ioctl flags * diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index dbf1a27..2cebb30 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -276,6 +276,10 @@ struct fuse_lowlevel_ops { * bitmask contain valid values. Other members contain undefined * values. * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits if the file + * size or owner is being changed. + * * If the setattr was invoked from the ftruncate() system call * under Linux kernel versions 2.6.15 or later, the fi->fh will * contain the value set by the open method or will be undefined @@ -509,6 +513,9 @@ struct fuse_lowlevel_ops { * of the write system call will reflect the return value of this * operation. * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. + * * fi->fh will contain the value set by the open method, or will * be undefined if the open method didn't set any value. * @@ -1013,6 +1020,9 @@ struct fuse_lowlevel_ops { * bufv->off is correctly updated (reflecting the number of * bytes read from bufv->buf[0]). * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. + * * Valid replies: * fuse_reply_write * fuse_reply_err diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 3941c7f..9386f1a 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -1879,6 +1879,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; if (arg->flags & FUSE_POSIX_ACL) se->conn.capable |= FUSE_CAP_POSIX_ACL; + if (arg->flags & FUSE_HANDLE_KILLPRIV) + se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV; } else { se->conn.max_readahead = 0; } @@ -1907,6 +1909,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ); LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS); LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA); + LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV); LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO); LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR); LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC); -- 2.30.2