Fix cleanup in case of failed mount
authorMiklos Szeredi <mszeredi@suse.cz>
Mon, 31 Jan 2011 15:32:46 +0000 (16:32 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Mon, 31 Jan 2011 16:40:49 +0000 (17:40 +0100)
In case of failure to add to /etc/mtab use same mountpoint for cleanup
as for mounting.  Reported by Marc Deslauriers

ChangeLog
util/fusermount.c

index ff1c04f72c0af5d53eff66054e9227b7a39d8c94..ba61398f06383c5a317a904bfd5522ca3694cc7c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,9 @@
        * Always call mount with --no-canonicalize option to prevent
        symlink attacks on mount.
 
+       * In case of failure to add to /etc/mtab use same mountpoint for
+       cleanup as for mounting.  Reported by Marc Deslauriers
+
 2010-11-08  Miklos Szeredi <miklos@szeredi.hu>
 
        * Open /dev/null for write instead of read for redirecting stdout
index 731f56d409d636ab766059b8af49f24c5341ee58..70c18b783186f189e91ca7471843f4db642394c9 100644 (file)
@@ -882,7 +882,7 @@ static int check_version(const char *dev)
 }
 
 static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
-                     int *mountpoint_fd)
+                     int *mountpoint_fd, int *isdir)
 {
        int res;
        const char *mnt = *mntp;
@@ -900,6 +900,7 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
                return 0;
 
        if (S_ISDIR(stbuf->st_mode)) {
+               *isdir = 1;
                *currdir_fd = open(".", O_RDONLY);
                if (*currdir_fd == -1) {
                        fprintf(stderr,
@@ -907,10 +908,16 @@ static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
                                progname, strerror(errno));
                        return -1;
                }
-               res = chdir(mnt);
+               *mountpoint_fd = open(mnt, O_RDONLY);
+               if (*mountpoint_fd == -1) {
+                       fprintf(stderr, "%s: failed to open %s: %s\n",
+                               progname, mnt, strerror(errno));
+                       return -1;
+               }
+               res = fchdir(*mountpoint_fd);
                if (res == -1) {
                        fprintf(stderr,
-                               "%s: failed to chdir to mountpoint: %s\n",
+                               "%s: failed to fchdir to mountpoint: %s\n",
                                progname, strerror(errno));
                        return -1;
                }
@@ -1036,6 +1043,7 @@ static int mount_fuse(const char *mnt, const char *opts)
        const char *real_mnt = mnt;
        int currdir_fd = -1;
        int mountpoint_fd = -1;
+       int isdir = 0;
 
        fd = open_fuse_device(&dev);
        if (fd == -1)
@@ -1056,7 +1064,7 @@ static int mount_fuse(const char *mnt, const char *opts)
        res = check_version(dev);
        if (res != -1) {
                res = check_perm(&real_mnt, &stbuf, &currdir_fd,
-                                &mountpoint_fd);
+                                &mountpoint_fd, &isdir);
                restore_privs();
                if (res != -1)
                        res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
@@ -1070,22 +1078,37 @@ static int mount_fuse(const char *mnt, const char *opts)
                close(currdir_fd);
        }
        if (mountpoint_fd != -1)
-               close(mountpoint_fd);
+               fcntl(mountpoint_fd, F_SETFD, FD_CLOEXEC);
 
        if (res == -1) {
                close(fd);
+               if (mountpoint_fd != -1)
+                       close(mountpoint_fd);
                return -1;
        }
 
        if (geteuid() == 0) {
                res = add_mount(source, mnt, type, mnt_opts);
                if (res == -1) {
-                       umount2(mnt, 2); /* lazy umount */
+                       if (isdir && mountpoint_fd != -1) {
+                               res = fchdir(mountpoint_fd);
+                               if (res == -1) {
+                                       close(mountpoint_fd);
+                                       close(fd);
+                                       return -1;
+                               }
+                       }
+                       umount2(real_mnt, 2); /* lazy umount */
+                       if (mountpoint_fd != -1)
+                               close(mountpoint_fd);
                        close(fd);
                        return -1;
                }
        }
 
+       if (mountpoint_fd != -1)
+               close(mountpoint_fd);
+
        free(source);
        free(type);
        free(mnt_opts);