diff options
author | Shawn Landden <slandden@gmail.com> | 2017-11-21 19:40:40 -0800 |
---|---|---|
committer | Shawn Landden <slandden@gmail.com> | 2018-02-26 15:19:54 -0800 |
commit | dfb45b528746bf89c030fccac307ebcf7c988511 (patch) | |
tree | be304288a6e27d29f0460f049acd8123a6882ea7 | |
parent | 23d362910b1a6b2dca8a8d49e84620dce7a1345a (diff) | |
download | distcc-git-dfb45b528746bf89c030fccac307ebcf7c988511.tar.gz |
access control on having masquerade set up for binary
fixes the very old CVE-2004-2687 https://github.com/distcc/distcc/issues/155
at least unless gcc or clang can be exploited into executing arbitrary code--
but that is much more difficult than the current exploit.
(C++ templates are turing complete [1], so it is probably possible)
[1] http://web.archive.org/web/20131101122512/http://ubietylab.net/ubigraph/content/Papers/pdf/CppTuring.pdf
-rw-r--r-- | src/serve.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/src/serve.c b/src/serve.c index 336a491..c9df132 100644 --- a/src/serve.c +++ b/src/serve.c @@ -357,6 +357,52 @@ static int dcc_check_compiler_masq(char *compiler_name) return 0; } +/** + * Make sure there is a masquerade to distcc in /usr/lib/distcc in order to + * execute a binary of the same name. + * + * Before this it was possible to execute arbitrary command after connecting + * to distcc, which is quite a security risk when combined with any local root + * privledge escalation exploit. See CVE 2004-2687 + * + * https://nvd.nist.gov/vuln/detail/CVE-2004-2687 + * https://github.com/distcc/distcc/issues/155 + **/ +static int dcc_check_compiler_whitelist(char *compiler_name) +{ + int dirfd = -1; + ssize_t len; + struct stat sb; + char linkbuf[MAXPATHLEN]; + + if (strchr(compiler_name, '/')) + return EXIT_BAD_ARGUMENTS; + + dirfd = open("/usr/lib/distcc", O_RDONLY); + if (dirfd < 0) { + if (errno == ENOENT) + rs_log_crit("no %s", "/usr/lib/distcc"); + return EXIT_DISTCC_FAILED; + } + + if (fstatat(dirfd, compiler_name, &sb, AT_SYMLINK_NOFOLLOW) == -1) + return EXIT_BAD_ARGUMENTS; /* ENOENT, EACCESS, etc */ + if (!S_ISLNK(sb.st_mode)) { + rs_trace("%s/%s is not a symlink", "/usr/lib/distcc", compiler_name); + return EXIT_BAD_ARGUMENTS; + } + if ((len = readlinkat(dirfd, compiler_name, linkbuf, sizeof linkbuf)) <= 0) + return EXIT_BAD_ARGUMENTS; + linkbuf[len] = '\0'; + + if (strstr(linkbuf, "distcc")) { + rs_trace("%s in /usr/lib/distcc whitelist", compiler_name); + return 0; + } else { + return EXIT_BAD_ARGUMENTS; + } +} + static const char *include_options[] = { "-I", "-include", @@ -669,11 +715,14 @@ static int dcc_run_job(int in_fd, } if (!dcc_remap_compiler(&argv[0])) - goto out_cleanup; + goto out_cleanup; if ((ret = dcc_check_compiler_masq(argv[0]))) goto out_cleanup; + if (dcc_check_compiler_whitelist(argv[0])) + goto out_cleanup; + if ((compile_ret = dcc_spawn_child(argv, &cc_pid, "/dev/null", out_fname, err_fname)) || (compile_ret = dcc_collect_child("cc", cc_pid, &status, in_fd))) { |