aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2013-06-20 11:43:02 +0200
committerMiklos Szeredi <mszeredi@suse.cz>2013-07-01 10:06:37 +0200
commitddfd2d44a6eab79c722f4b5785efdbcccb9c4d35 (patch)
tree9d3b4d9ae8a687c97761b2200f448bf88ad2c53e
parent44088bc7fbe7c9234c090756dbf10742b1a281b1 (diff)
downloadandroid_external_fuse-ddfd2d44a6eab79c722f4b5785efdbcccb9c4d35.tar.gz
android_external_fuse-ddfd2d44a6eab79c722f4b5785efdbcccb9c4d35.tar.bz2
android_external_fuse-ddfd2d44a6eab79c722f4b5785efdbcccb9c4d35.zip
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
-rw-r--r--ChangeLog5
-rw-r--r--lib/fuse_i.h2
-rw-r--r--lib/fuse_session.c7
-rw-r--r--lib/helper.c10
-rw-r--r--lib/mount.c12
-rw-r--r--lib/mount_bsd.c9
6 files changed, 34 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 3afa404..2e902f5 100644
--- 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
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 78f1467..fa37156 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -106,6 +106,8 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
size_t op_size, void *userdata);
void fuse_kern_unmount_compat22(const char *mountpoint);
+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/fuse_session.c b/lib/fuse_session.c
index c55f250..6e11068 100644
--- a/lib/fuse_session.c
+++ b/lib/fuse_session.c
@@ -182,6 +182,13 @@ int fuse_chan_fd(struct fuse_chan *ch)
return ch->fd;
}
+int fuse_chan_clearfd(struct fuse_chan *ch)
+{
+ int fd = ch->fd;
+ ch->fd = -1;
+ return fd;
+}
+
size_t fuse_chan_bufsize(struct fuse_chan *ch)
{
return ch->bufsize;
diff --git a/lib/helper.c b/lib/helper.c
index ace19dd..b644012 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -249,10 +249,12 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
static void fuse_unmount_common(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);
+ }
}
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
diff --git a/lib/mount.c b/lib/mount.c
index 6a9da9e..0f767c8 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -300,14 +300,18 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
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 62443ac..3aec3e3 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 */