Always call umount with --no-canonicalize --fake options
authorMiklos Szeredi <mszeredi@suse.cz>
Mon, 31 Jan 2011 16:40:49 +0000 (17:40 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Mon, 31 Jan 2011 16:40:49 +0000 (17:40 +0100)
Always call umount with --no-canonicalize --fake options to prevent
symlink attacks at umount.  util-linux >= 2.18 or a suitably patched
version is required.

ChangeLog
lib/mount_util.c
lib/mount_util.h
util/fusermount.c

index fb3504beb662faa377099cd2e39eeeef7fb851c6..49f4e71028847a466b0c06adb2ca372e07de9a1d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-01-31  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Always call umount with --no-canonicalize --fake options to
+       prevent symlink attacks at umount.  util-linux >= 2.18 or a
+       suitably patched version is required.
+
 2010-11-08  Miklos Szeredi <miklos@szeredi.hu>
 
        * Open /dev/null for write instead of read for redirecting stdout
index 5469c1b9b64b0ebac7e6c523c788dd3d5dc6077c..4230e637b77f415a6e2dbf273c91514e8648ad22 100644 (file)
@@ -243,6 +243,55 @@ int fuse_mnt_umount(const char *progname, const char *abs_mnt,
        return exec_umount(progname, rel_mnt, lazy);
 }
 
+static int remove_mount(const char *progname, const char *mnt)
+{
+       int res;
+       int status;
+       sigset_t blockmask;
+       sigset_t oldmask;
+
+       sigemptyset(&blockmask);
+       sigaddset(&blockmask, SIGCHLD);
+       res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+       if (res == -1) {
+               fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+               return -1;
+       }
+
+       res = fork();
+       if (res == -1) {
+               fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+               goto out_restore;
+       }
+       if (res == 0) {
+               sigprocmask(SIG_SETMASK, &oldmask, NULL);
+               setuid(geteuid());
+               execl("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
+                     "--fake", mnt, NULL);
+               fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
+                       progname, strerror(errno));
+               exit(1);
+       }
+       res = waitpid(res, &status, 0);
+       if (res == -1)
+               fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+       if (status != 0)
+               res = -1;
+
+ out_restore:
+       sigprocmask(SIG_SETMASK, &oldmask, NULL);
+       return res;
+}
+
+int fuse_mnt_remove_mount(const char *progname, const char *mnt)
+{
+       if (!mtab_needs_update(mnt))
+               return 0;
+
+       return remove_mount(progname, mnt);
+}
+
 char *fuse_mnt_resolve_path(const char *progname, const char *orig)
 {
        char buf[PATH_MAX];
index f392f99f17a7129cc78233073aef0a9c656f533c..dc5c916f128a2789ddbc175b3b0716e12715b00c 100644 (file)
@@ -10,6 +10,7 @@
 
 int fuse_mnt_add_mount(const char *progname, const char *fsname,
                       const char *mnt, const char *type, const char *opts);
+int fuse_mnt_remove_mount(const char *progname, const char *mnt);
 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
                    const char *rel_mnt, int lazy);
 char *fuse_mnt_resolve_path(const char *progname, const char *orig);
index 39da9b6a0b6fa1f36d6e1a1a5d28c0fbbe64570f..731f56d409d636ab766059b8af49f24c5341ee58 100644 (file)
@@ -407,8 +407,15 @@ static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
        if (res == -1)
                goto out;
 
-       res = fuse_mnt_umount(progname, mnt, last, lazy);
+       res = umount2(last, lazy ? 2 : 0);
+       if (res == -1 && !quiet) {
+               fprintf(stderr,
+                       "%s: failed to unmount %s: %s\n",
+                       progname, mnt, strerror(errno));
+       }
 
+       if (res == 0)
+               res = fuse_mnt_remove_mount(progname, mnt);
 out:
        free(copy);
        if (currdir_fd != -1) {