From 0bd509a28f93d46e49191de05da5f547311f4ab4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sat, 31 Mar 2012 10:08:51 -0400 Subject: [PATCH] mount.cifs: don't allow unprivileged users to mount onto dirs to which they can't chdir If mount.cifs is installed as a setuid root program, then a user can use it to gather information about files and directories to which he does not have access. One of the first things that mount.cifs does is to chdir() into the mountpoint and then proceeds to perform the mount onto ".". A malicious user could exploit this fact to determine information about directories to which he does not have access. Specifically, whether the dentry in question is a file or directory and whether it exists at all. This patch fixes this by making the program switch the fsuid to the real uid for unprivileged users when mounting. This patch should fix CVE-2012-1586. Reported-by: Jesus Olmos Signed-off-by: Jeff Layton --- mount.cifs.c | 83 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 64 insertions(+), 19 deletions(-) diff --git a/mount.cifs.c b/mount.cifs.c index c0aea35..ed3a16d 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -45,6 +45,7 @@ #include #include #include +#include #ifdef HAVE_LIBCAP_NG #include #else /* HAVE_LIBCAP_NG */ @@ -1854,6 +1855,68 @@ assemble_exit: return rc; } +/* + * chdir() into the mountpoint and determine "realpath". We assume here that + * "mountpoint" is a statically allocated string and does not need to be freed. + */ +static int +acquire_mountpoint(char **mountpointp) +{ + int rc, dacrc; + uid_t realuid, oldfsuid; + gid_t oldfsgid; + char *mountpoint; + + /* + * Acquire the necessary privileges to chdir to the mountpoint. If + * the real uid is root, then we reacquire CAP_DAC_READ_SEARCH. If + * it's not, then we change the fsuid to the real uid to ensure that + * the mounting user actually has access to the mountpoint. + * + * The mount(8) manpage does not state that users must be able to + * chdir into the mountpoint in order to mount onto it, but if we + * allow that, then an unprivileged user could use this program to + * "probe" into directories to which he does not have access. + */ + realuid = getuid(); + if (realuid == 0) { + dacrc = toggle_dac_capability(0, 1); + if (dacrc) + return dacrc; + } else { + oldfsuid = setfsuid(realuid); + oldfsgid = setfsgid(getgid()); + } + + rc = chdir(*mountpointp); + if (rc) { + fprintf(stderr, "Couldn't chdir to %s: %s\n", *mountpointp, + strerror(errno)); + rc = EX_USAGE; + goto restore_privs; + } + + mountpoint = realpath(".", NULL); + if (!mountpoint) { + fprintf(stderr, "Unable to resolve %s to canonical path: %s\n", + *mountpointp, strerror(errno)); + rc = EX_SYSERR; + } + + *mountpointp = mountpoint; +restore_privs: + if (realuid == 0) { + dacrc = toggle_dac_capability(0, 0); + if (dacrc) + rc = rc ? rc : dacrc; + } else { + setfsuid(oldfsuid); + setfsgid(oldfsgid); + } + + return rc; +} + int main(int argc, char **argv) { int c; @@ -1953,25 +2016,7 @@ int main(int argc, char **argv) mountpoint = argv[optind + 1]; /* chdir into mountpoint as soon as possible */ - rc = toggle_dac_capability(0, 1); - if (rc) - return rc; - rc = chdir(mountpoint); - if (rc) { - fprintf(stderr, "Couldn't chdir to %s: %s\n", mountpoint, - strerror(errno)); - rc = EX_USAGE; - goto mount_exit; - } - - mountpoint = realpath(".", NULL); - if (!mountpoint) { - fprintf(stderr, "Unable to resolve %s to canonical path: %s\n", - mountpoint, strerror(errno)); - rc = EX_SYSERR; - goto mount_exit; - } - rc = toggle_dac_capability(0, 0); + rc = acquire_mountpoint(&mountpoint); if (rc) return rc; -- 1.7.7.6