From ea8d5594b1432589ba286e4501c5f6dcba3d8dab Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 31 Jan 2011 17:40:49 +0100 Subject: [PATCH] Always call umount with --no-canonicalize --fake options 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 | 6 ++++++ lib/mount_util.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ lib/mount_util.h | 1 + util/fusermount.c | 9 ++++++++- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index fb3504b..49f4e71 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2011-01-31 Miklos Szeredi + + * 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 * Open /dev/null for write instead of read for redirecting stdout diff --git a/lib/mount_util.c b/lib/mount_util.c index 5469c1b..4230e63 100644 --- a/lib/mount_util.c +++ b/lib/mount_util.c @@ -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]; diff --git a/lib/mount_util.h b/lib/mount_util.h index f392f99..dc5c916 100644 --- a/lib/mount_util.h +++ b/lib/mount_util.h @@ -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); diff --git a/util/fusermount.c b/util/fusermount.c index 39da9b6..731f56d 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -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) { -- 2.30.2