]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
fuse2fs: delegate access control decisions to the kernel
authorDarrick J. Wong <djwong@kernel.org>
Thu, 24 Apr 2025 21:45:28 +0000 (14:45 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 21 May 2025 14:26:54 +0000 (10:26 -0400)
In "kernel" mode (aka allow_others + default_permissions), the kernel
enforces all the access control for us.  Therefore, we don't need to do
any checking of our own.  Create a purpose-built helper to detect this
situation and turn off all the access controlling.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/174553065373.1161102.14873909355987419902.stgit@frogsfrogsfrogs
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
misc/fuse2fs.c

index dd7559bb2af2b3dd1f517af78276f21462eec7b4..eac52d66b21a38055e85bacdf2ec38aea18dee9e 100644 (file)
@@ -491,6 +491,18 @@ static inline int is_superuser(struct fuse2fs *ff, struct fuse_context *ctxt)
        return ctxt->uid == 0;
 }
 
+static inline int want_check_owner(struct fuse2fs *ff,
+                                  struct fuse_context *ctxt)
+{
+       /*
+        * The kernel is responsible for access control, so we allow anything
+        * that the superuser can do.
+        */
+       if (ff->kernel)
+               return 0;
+       return !is_superuser(ff, ctxt);
+}
+
 static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
 {
        struct fuse_context *ctxt = fuse_get_context();
@@ -523,6 +535,10 @@ static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
            (inode.i_flags & EXT2_IMMUTABLE_FL))
                return -EACCES;
 
+       /* If kernel is responsible for mode and acl checks, we're done. */
+       if (ff->kernel)
+               return 0;
+
        /* Figure out what root's allowed to do */
        if (is_superuser(ff, ctxt)) {
                /* Non-file access always ok */
@@ -1808,7 +1824,7 @@ static int op_chmod(const char *path, mode_t mode
                goto out;
        }
 
-       if (!is_superuser(ff, ctxt) && ctxt->uid != inode_uid(inode)) {
+       if (want_check_owner(ff, ctxt) && ctxt->uid != inode_uid(inode)) {
                ret = -EPERM;
                goto out;
        }
@@ -1875,7 +1891,7 @@ static int op_chown(const char *path, uid_t owner, gid_t group
        /* FUSE seems to feed us ~0 to mean "don't change" */
        if (owner != (uid_t) ~0) {
                /* Only root gets to change UID. */
-               if (!is_superuser(ff, ctxt) &&
+               if (want_check_owner(ff, ctxt) &&
                    !(inode_uid(inode) == ctxt->uid && owner == ctxt->uid)) {
                        ret = -EPERM;
                        goto out;
@@ -1886,7 +1902,7 @@ static int op_chown(const char *path, uid_t owner, gid_t group
 
        if (group != (gid_t) ~0) {
                /* Only root or the owner get to change GID. */
-               if (!is_superuser(ff, ctxt) &&
+               if (want_check_owner(ff, ctxt) &&
                    inode_uid(inode) != ctxt->uid) {
                        ret = -EPERM;
                        goto out;
@@ -3051,7 +3067,7 @@ static int ioctl_setflags(struct fuse2fs *ff, struct fuse2fs_file_handle *fh,
        if (err)
                return translate_error(fs, fh->ino, err);
 
-       if (!is_superuser(ff, ctxt) && inode_uid(inode) != ctxt->uid)
+       if (want_check_owner(ff, ctxt) && inode_uid(inode) != ctxt->uid)
                return -EPERM;
 
        ret = set_iflags(&inode, flags);
@@ -3107,7 +3123,7 @@ static int ioctl_setversion(struct fuse2fs *ff, struct fuse2fs_file_handle *fh,
        if (err)
                return translate_error(fs, fh->ino, err);
 
-       if (!is_superuser(ff, ctxt) && inode_uid(inode) != ctxt->uid)
+       if (want_check_owner(ff, ctxt) && inode_uid(inode) != ctxt->uid)
                return -EPERM;
 
        inode.i_generation = generation;
@@ -3213,7 +3229,7 @@ static int ioctl_fssetxattr(struct fuse2fs *ff, struct fuse2fs_file_handle *fh,
        if (err)
                return translate_error(fs, fh->ino, err);
 
-       if (!is_superuser(ff, ctxt) && inode_uid(inode) != ctxt->uid)
+       if (want_check_owner(ff, ctxt) && inode_uid(inode) != ctxt->uid)
                return -EPERM;
 
        ret = set_iflags(&inode, flags);