libfuse: fix multiple close of device fd
authorMiklos Szeredi <mszeredi@suse.cz>
Thu, 20 Jun 2013 09:43:02 +0000 (11:43 +0200)
committerMiklos Szeredi <mszeredi@suse.cz>
Thu, 20 Jun 2013 09:43:02 +0000 (11:43 +0200)
- fuse_kern_unmount closes handle (e.g. 19)
- a thread in my process opens a file - the OS assigns newly freed
handle (i.e. 19)
- fuse_kern_chan_destroy closes the same handle (i.e. 19)
- a thread in my process opens another file - the OS assigns newly
freed handle (i.e. 19)
- * MAYHEM *

Reported by Dan Greenfield

ChangeLog
lib/fuse_i.h
lib/helper.c
lib/mount.c
lib/mount_bsd.c

index a543264a8d94e527e78b796343166778a7adc6d6..1d6f9e8094f606ad32d2b03b09478852d933a74d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-06-20  Miklos Szeredi <miklos@szeredi.hu>
+
+       * libfuse: fix multiple close of device fd.  Reported by Dan
+       Greenfield
+
 2013-03-19  Miklos Szeredi <miklos@szeredi.hu>
 
        * libfuse: fix thread cancel race.  Exiting a worker my race with
index ffcf062cd6294f467dead8efc22a57f6e254e572..33fbb434c80dd4da8fa6039a7302ca0356ec4c5e 100644 (file)
@@ -93,6 +93,8 @@ struct fuse_ll {
 
 struct fuse_chan *fuse_kern_chan_new(int fd);
 
+int fuse_chan_clearfd(struct fuse_chan *ch);
+
 void fuse_kern_unmount(const char *mountpoint, int fd);
 int fuse_kern_mount(const char *mountpoint, struct fuse_args *args);
 
index 8ee66df0be665763550344176d933c809efd93ee..58dfb4344c3bf941c52d121e305d37c2ceda48f1 100644 (file)
@@ -244,10 +244,12 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
 
 void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
 {
-       int fd = ch ? fuse_chan_fd(ch) : -1;
-       fuse_kern_unmount(mountpoint, fd);
-       if (ch)
-               fuse_chan_destroy(ch);
+       if (mountpoint) {
+               int fd = ch ? fuse_chan_clearfd(ch) : -1;
+               fuse_kern_unmount(mountpoint, fd);
+               if (ch)
+                       fuse_chan_destroy(ch);
+       }
 }
 
 static struct fuse *fuse_setup(int argc, char *argv[],
index 4f748417466b438e696b9d7d7bb61a86996bcdbf..d7ba57173ebdb2bce8c6069b11140f738e9dad71 100644 (file)
@@ -294,23 +294,24 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
        int res;
        int pid;
 
-       if (!mountpoint)
-               return;
-
        if (fd != -1) {
                struct pollfd pfd;
 
                pfd.fd = fd;
                pfd.events = 0;
                res = poll(&pfd, 1, 0);
+
+               /* Need to close file descriptor, otherwise synchronous umount
+                  would recurse into filesystem, and deadlock.
+
+                  Caller expects fuse_kern_unmount to close the fd, so close it
+                  anyway. */
+               close(fd);
+
                /* If file poll returns POLLERR on the device file descriptor,
                   then the filesystem is already unmounted */
                if (res == 1 && (pfd.revents & POLLERR))
                        return;
-
-               /* Need to close file descriptor, otherwise synchronous umount
-                  would recurse into filesystem, and deadlock */
-               close(fd);
        }
 
        if (geteuid() == 0) {
index 9ee74fb14b628fceb8556f06d7911c234b4c990b..36c5a2bade40535dbc2745357194d99c33459b2b 100644 (file)
@@ -228,18 +228,21 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
        (void)mountpoint;
 
        if (fstat(fd, &sbuf) == -1)
-               return;
+               goto out;
 
        devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
 
        if (strncmp(dev, "fuse", 4))
-               return;
+               goto out;
 
        strtol(dev + 4, &ep, 10);
        if (*ep != '\0')
-               return;
+               goto out;
 
        do_unmount(dev, fd);
+
+out:
+       close(fd);
 }
 
 /* Check if kernel is doing init in background */