]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: Support unmount FUSE mounts
authorRian Hunter <rian@alum.mit.edu>
Sat, 13 Oct 2018 02:48:47 +0000 (19:48 -0700)
committerKarel Zak <kzak@redhat.com>
Fri, 30 Nov 2018 09:25:04 +0000 (10:25 +0100)
FUSE mounts don't need an fstab entry to be unmounted.
This checks if a mount is a FUSE mount before checking for
the fstab entry, and if so returns success.

[kzak@redhat.com: - use libmount tools for mount options
                  - use namespace switches
                  - cleanup code

 The requirement is user=<username> or user_id=<uid> in /proc/self/mountinfo
 for fuse filesystem. The logic is the same as for user= mount options, but in
 this case it is not maintained by libmount in userspace, but by fuse FS in kernel.]

Co-Author: Karel Zak <kzak@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/context_umount.c

index d72f5ccd0d81fbd85d4b59c5f91cb3b1e893898d..03c55ff61985933c936310aea2c51fbfba8f38b8 100644 (file)
@@ -388,6 +388,75 @@ static int prepare_helper_from_options(struct libmnt_context *cxt,
        return rc;
 }
 
+static int is_fuse_usermount(struct libmnt_context *cxt, int *errsv)
+{
+       struct libmnt_ns *ns_old;
+       const char *type = mnt_fs_get_fstype(cxt->fs);
+       const char *optstr;
+       char *user = NULL, *user_id = NULL, *curr_user = NULL;
+       size_t sz;
+       uid_t uid;
+       int ok = 0;
+
+       *errsv = 0;
+
+       if (!type)
+               return 0;
+
+       if (strcmp(type, "fuse") != 0 &&
+           strcmp(type, "fuseblk") != 0 &&
+           strncmp(type, "fuse.", 5) != 0 &&
+           strncmp(type, "fuseblk.", 8) != 0)
+               return 0;
+
+       /* get user= or user_id= from mtab/mountinfo */
+       optstr = mnt_fs_get_user_options(cxt->fs);
+       if (!optstr)
+               return 0;
+
+       if (mnt_optstr_get_option(optstr, "user", &user, &sz) != 0 &&
+           mnt_optstr_get_option(optstr, "user_id", &user_id, &sz) != 0)
+               return 0;
+
+       if (sz == 0 || (user == NULL && user_id == NULL))
+               return 0;
+
+       /* get current user */
+       ns_old = mnt_context_switch_origin_ns(cxt);
+       if (!ns_old) {
+               *errsv = -MNT_ERR_NAMESPACE;
+               return 0;
+       }
+
+       uid = getuid();
+       if (user)
+               curr_user = mnt_get_username(uid);
+
+       if (!mnt_context_switch_ns(cxt, ns_old)) {
+               *errsv = -MNT_ERR_NAMESPACE;
+               return 0;
+       }
+
+       if (user && !curr_user) {
+               DBG(CXT, ul_debugobj(cxt, "umount (fuse): cannot "
+                               "convert %d to username", uid));
+               return 0;
+       }
+
+       if (user)
+               ok = strncmp(curr_user, user, sz) == 0;
+
+       else if (user_id) {
+               char uidstr[sizeof(stringify_value(ULONG_MAX))];
+               snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long) uid);
+
+               ok = strncmp(user_id, uidstr, sz) == 0;
+       }
+
+       free(curr_user);
+       return ok;
+}
+
 /*
  * Note that cxt->fs contains relevant mtab entry!
  */
@@ -396,7 +465,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
        struct libmnt_table *fstab;
        unsigned long u_flags = 0;
        const char *tgt, *src, *optstr;
-       int rc, ok = 0;
+       int rc = 0, ok = 0;
        struct libmnt_fs *fs;
 
        assert(cxt);
@@ -424,6 +493,17 @@ static int evaluate_permissions(struct libmnt_context *cxt)
                        return 0;       /* we'll call /sbin/umount.<uhelper> */
        }
 
+       /*
+        * Check if this is a fuse mount for the current user,
+        * if so then unmounting is allowed
+        */
+       if (is_fuse_usermount(cxt, &rc)) {
+               DBG(CXT, ul_debugobj(cxt, "fuse user mount, umount is allowed"));
+               return 0;
+       }
+       if (rc)
+               return rc;
+
        /*
         * User mounts have to be in /etc/fstab
         */