Add support for FUSE_HANDLE_KILLPRIV
authorNikolaus Rath <Nikolaus@rath.org>
Tue, 22 Nov 2016 23:56:55 +0000 (15:56 -0800)
committerNikolaus Rath <Nikolaus@rath.org>
Tue, 22 Nov 2016 23:56:55 +0000 (15:56 -0800)
Fixes #116.

ChangeLog.rst
include/fuse.h
include/fuse_common.h
include/fuse_lowlevel.h
lib/fuse_lowlevel.c

index 9c1a5dd6aca2ce140789c86cfd10e91aae9b4d15..999f4318d780e55fad47b345992054035b257083 100644 (file)
@@ -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)
 ===========================
index 60015cae5b972eb3f96ec0ec8a92e263d4d947ca..56539f10e79b4ef0900584c31d6dc971e6748a26 100644 (file)
@@ -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 *);
index f3361291a0a52509a2bd74400ddd9ebae93b9c30..04b378f5ba047158d46374423616bfaccd0cdc0e 100644 (file)
@@ -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
  *
index dbf1a2784d1c5073a75b2dce551da61781832587..2cebb30bb058c32592bea1e05e8736eea6a11581 100644 (file)
@@ -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
index 3941c7f75ba0a6563632f52015d427edfd565813..9386f1a0042b314f6eff1b63df50b5f80d658fa2 100644 (file)
@@ -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);