From: Miklos Szeredi Date: Thu, 20 Jun 2013 09:43:02 +0000 (+0200) Subject: libfuse: fix multiple close of device fd X-Git-Tag: fuse-3.0.0pre0~118 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=af57c73304b8a23c6ca0e1aebf4ce49071ac784a;p=qemu-gpiodev%2Flibfuse.git libfuse: fix multiple close of device fd - 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 --- diff --git a/ChangeLog b/ChangeLog index a543264..1d6f9e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-06-20 Miklos Szeredi + + * libfuse: fix multiple close of device fd. Reported by Dan + Greenfield + 2013-03-19 Miklos Szeredi * libfuse: fix thread cancel race. Exiting a worker my race with diff --git a/lib/fuse_i.h b/lib/fuse_i.h index ffcf062..33fbb43 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -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); diff --git a/lib/helper.c b/lib/helper.c index 8ee66df..58dfb43 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -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[], diff --git a/lib/mount.c b/lib/mount.c index 4f74841..d7ba571 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -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) { diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 9ee74fb..36c5a2b 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -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 */