diff options
Diffstat (limited to 'meta/recipes-extended/sudo/sudo/CVE-2015-8239-1.patch')
-rw-r--r-- | meta/recipes-extended/sudo/sudo/CVE-2015-8239-1.patch | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/meta/recipes-extended/sudo/sudo/CVE-2015-8239-1.patch b/meta/recipes-extended/sudo/sudo/CVE-2015-8239-1.patch new file mode 100644 index 0000000000..582c0bf638 --- /dev/null +++ b/meta/recipes-extended/sudo/sudo/CVE-2015-8239-1.patch @@ -0,0 +1,699 @@ +# HG changeset patch +# User Todd C. Miller <Todd.Miller@courtesan.com> +# Date 1451928918 25200 +# Node ID 397722cdd7eceef0aec561909418215e275ccd44 +# Parent 33272418bb10ee780184dbd2d966a4e5c3bc597e +Add support for using fexecve() if supported on commands that are +checksummed. + +Reference to upstream patch: +https://www.sudo.ws/repos/sudo/rev/397722cdd7ec + +CVE: CVE-2015-8239 +Upstream-Status: Backport +Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> +--- +diff -ruN a/configure b/configure +--- a/configure 2015-11-01 00:35:24.000000000 +0100 ++++ b/configure 2016-08-08 12:56:03.441681854 +0200 +@@ -2650,6 +2650,7 @@ + as_fn_append ac_header_list " sys/select.h" + as_fn_append ac_header_list " sys/stropts.h" + as_fn_append ac_header_list " sys/sysmacros.h" ++as_fn_append ac_func_list " fexecve" + as_fn_append ac_func_list " killpg" + as_fn_append ac_func_list " nl_langinfo" + as_fn_append ac_func_list " strftime" +@@ -18078,6 +18079,8 @@ + + + ++ ++ + for ac_func in getgrouplist + do : + ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist" +@@ -19903,8 +19906,8 @@ + fi + done + +- # Check for fexecve, posix_spawn, and posix_spawnp +- for ac_func in fexecve posix_spawn posix_spawnp ++ # Check for posix_spawn, and posix_spawnp ++ for ac_func in posix_spawn posix_spawnp + do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +diff -ruN a/configure.ac b/configure.ac +--- a/configure.ac 2016-08-08 12:55:08.781888802 +0200 ++++ b/configure.ac 2016-08-08 12:56:03.445681547 +0200 +@@ -1,7 +1,7 @@ + dnl + dnl Use the top-level autogen.sh script to generate configure and config.h.in + dnl +-dnl Copyright (c) 1994-1996,1998-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++dnl Copyright (c) 1994-1996,1998-2016 Todd C. Miller <Todd.Miller@courtesan.com> + dnl + AC_PREREQ([2.59]) + AC_INIT([sudo], [1.8.15], [http://www.sudo.ws/bugs/], [sudo]) +@@ -2384,7 +2384,7 @@ + dnl Function checks + dnl + AC_FUNC_GETGROUPS +-AC_CHECK_FUNCS_ONCE([killpg nl_langinfo strftime pread pwrite openat]) ++AC_CHECK_FUNCS_ONCE([fexecve killpg nl_langinfo strftime pread pwrite openat]) + AC_CHECK_FUNCS([getgrouplist], [], [ + case "$host_os" in + aix*) +@@ -2676,8 +2676,8 @@ + if test X"$with_noexec" != X"no"; then + # Check for non-standard exec functions + AC_CHECK_FUNCS([exect execvP execvpe]) +- # Check for fexecve, posix_spawn, and posix_spawnp +- AC_CHECK_FUNCS([fexecve posix_spawn posix_spawnp]) ++ # Check for posix_spawn, and posix_spawnp ++ AC_CHECK_FUNCS([posix_spawn posix_spawnp]) + fi + + dnl +diff -ruN a/doc/sudoers.cat b/doc/sudoers.cat +--- a/doc/sudoers.cat 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudoers.cat 2016-08-08 12:56:03.445681547 +0200 +@@ -410,6 +410,13 @@ + $ openssl dgst -binary -sha224 /bin/ls | openssl base64 + EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ== + ++ Warning, if the user has write access to the command itself (directly or ++ via a sudo command), it may be possible for the user to replace the ++ command after the digest check has been performed but before the command ++ is executed. A similar race condition exists on systems that lack the ++ fexecve(2) system call when the directory in which the command is located ++ is writable by the user. ++ + Command digests are only supported by version 1.8.7 or higher. + + DDeeffaauullttss +diff -ruN a/doc/sudoers.man.in b/doc/sudoers.man.in +--- a/doc/sudoers.man.in 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudoers.man.in 2016-08-08 12:56:03.445681547 +0200 +@@ -1,7 +1,7 @@ + .\" DO NOT EDIT THIS FILE, IT IS NOT THE MASTER! + .\" IT IS GENERATED AUTOMATICALLY FROM sudoers.mdoc.in + .\" +-.\" Copyright (c) 1994-1996, 1998-2005, 2007-2015 ++.\" Copyright (c) 1994-1996, 1998-2005, 2007-2016 + .\" Todd C. Miller <Todd.Miller@courtesan.com> + .\" + .\" Permission to use, copy, modify, and distribute this software for any +@@ -877,6 +877,15 @@ + .RE + .fi + .PP ++Warning, if the user has write access to the command itself (directly or via a ++ \fBsudo\fR ++command), it may be possible for the user to replace the command after the ++digest check has been performed but before the command is executed. ++A similar race condition exists on systems that lack the ++fexecve(2) ++system call when the directory in which the command is located ++is writable by the user. ++ .PP + Command digests are only supported by version 1.8.7 or higher. + .SS "Defaults" + Certain configuration options may be changed from their default +diff -ruN a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in +--- a/doc/sudoers.mdoc.in 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudoers.mdoc.in 2016-08-08 12:56:03.449681239 +0200 +@@ -1,5 +1,5 @@ + .\" +-.\" Copyright (c) 1994-1996, 1998-2005, 2007-2015 ++.\" Copyright (c) 1994-1996, 1998-2005, 2007-2016 + .\" Todd C. Miller <Todd.Miller@courtesan.com> + .\" + .\" Permission to use, copy, modify, and distribute this software for any +@@ -834,6 +834,15 @@ + EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ== + .Ed + .Pp ++Warning, if the user has write access to the command itself (directly or via a ++ .Nm sudo ++command), it may be possible for the user to replace the command after the ++digest check has been performed but before the command is executed. ++A similar race condition exists on systems that lack the ++.Xr fexecve 2 ++system call when the directory in which the command is located ++is writable by the user. ++ .Pp + Command digests are only supported by version 1.8.7 or higher. + .Ss Defaults + Certain configuration options may be changed from their default +diff -ruN a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat +--- a/doc/sudo_plugin.cat 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudo_plugin.cat 2016-08-08 12:56:03.449681239 +0200 +@@ -499,6 +499,11 @@ + This setting has no effect unless I/O logging is + enabled or _u_s_e___p_t_y is enabled. + ++ execfd=number ++ If specified, ssuuddoo will use the fexecve(2) system call ++ to execute the command instead of execve(2). The ++ specified _n_u_m_b_e_r must refer to an open file descriptor. ++ + iolog_compress=bool + Set to true if the I/O logging plugins, if any, should + compress the log data. This is a hint to the I/O +@@ -1505,6 +1510,9 @@ + it supports plugin API version 1.8 or higher to receive a + conversation function pointer that supports this argument. + ++ Version 1.9 (sudo 1.8.16) ++ The _e_x_e_c_f_d entry was added to the command_info list. ++ + SSEEEE AALLSSOO + sudo.conf(4), sudoers(4), sudo(1m) + +diff -ruN a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in +--- a/doc/sudo_plugin.man.in 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudo_plugin.man.in 2016-08-08 12:56:03.449681239 +0200 +@@ -1,7 +1,7 @@ + .\" DO NOT EDIT THIS FILE, IT IS NOT THE MASTER! + .\" IT IS GENERATED AUTOMATICALLY FROM sudo_plugin.mdoc.in + .\" +-.\" Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++.\" Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + .\" + .\" Permission to use, copy, modify, and distribute this software for any + .\" purpose with or without fee is hereby granted, provided that the above +@@ -881,6 +881,17 @@ + \fIuse_pty\fR + is enabled. + .TP 6n ++execfd=number ++If specified, ++\fBsudo\fR ++will use the ++fexecve(2) ++system call to execute the command instead of ++execve(2). ++The specified ++\fInumber\fR ++must refer to an open file descriptor. ++.TP 6n + iolog_compress=bool + Set to true if the I/O logging plugins, if any, should compress the + log data. +@@ -2703,6 +2714,13 @@ + definition has been updated to match. + The plugin must specify that it supports plugin API version 1.8 or higher + to receive a conversation function pointer that supports this argument. ++.TP 6n ++Version 1.9 (sudo 1.8.16) ++The ++\fIexecfd\fR ++entry was added to the ++\fRcommand_info\fR ++list. + .SH "SEE ALSO" + sudo.conf(@mansectform@), + sudoers(@mansectform@), +diff -ruN a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in +--- a/doc/sudo_plugin.mdoc.in 2016-08-08 12:55:08.781888802 +0200 ++++ b/doc/sudo_plugin.mdoc.in 2016-08-08 12:56:03.453680931 +0200 +@@ -1,5 +1,5 @@ + .\" +-.\" Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++.\" Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + .\" + .\" Permission to use, copy, modify, and distribute this software for any + .\" purpose with or without fee is hereby granted, provided that the above +@@ -784,6 +784,16 @@ + This setting has no effect unless I/O logging is enabled or + .Em use_pty + is enabled. ++.It execfd=number ++If specified, ++.Nm sudo ++will use the ++.Xr fexecve 2 ++system call to execute the command instead of ++.Xr execve 2 . ++The specified ++.Em number ++must refer to an open file descriptor. + .It iolog_compress=bool + Set to true if the I/O logging plugins, if any, should compress the + log data. +@@ -2367,6 +2377,12 @@ + definition has been updated to match. + The plugin must specify that it supports plugin API version 1.8 or higher + to receive a conversation function pointer that supports this argument. ++.It Version 1.9 (sudo 1.8.16) ++The ++.Em execfd ++entry was added to the ++.Li command_info ++list. + .El + .Sh SEE ALSO + .Xr sudo.conf @mansectform@ , +diff -ruN a/include/sudo_plugin.h b/include/sudo_plugin.h +--- a/include/sudo_plugin.h 2016-08-08 12:55:08.781888802 +0200 ++++ b/include/sudo_plugin.h 2016-08-08 12:56:03.453680931 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -19,7 +19,7 @@ + + /* API version major/minor */ + #define SUDO_API_VERSION_MAJOR 1 +-#define SUDO_API_VERSION_MINOR 8 ++#define SUDO_API_VERSION_MINOR 9 + #define SUDO_API_MKVERSION(x, y) (((x) << 16) | (y)) + #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) + +diff -ruN a/plugins/sudoers/match.c b/plugins/sudoers/match.c +--- a/plugins/sudoers/match.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/plugins/sudoers/match.c 2016-08-08 12:56:03.453680931 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1996, 1998-2005, 2007-2015 ++ * Copyright (c) 1996, 1998-2005, 2007-2016 + * Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any +@@ -55,6 +55,7 @@ + # include <netdb.h> + #endif /* HAVE_NETGROUP_H */ + #include <dirent.h> ++#include <fcntl.h> + #include <pwd.h> + #include <grp.h> + #include <errno.h> +@@ -583,17 +584,18 @@ + }; + + static bool +-digest_matches(const char *file, const struct sudo_digest *sd) ++digest_matches(const char *file, const struct sudo_digest *sd, int *fd) + { + unsigned char file_digest[SHA512_DIGEST_LENGTH]; + unsigned char sudoers_digest[SHA512_DIGEST_LENGTH]; + unsigned char buf[32 * 1024]; + struct digest_function *func = NULL; ++ bool first = true; ++ bool is_script = false; + size_t nread; + SHA2_CTX ctx; + FILE *fp; + unsigned int i; +- int h; + debug_decl(digest_matches, SUDOERS_DEBUG_MATCH) + + for (i = 0; digest_functions[i].digest_name != NULL; i++) { +@@ -609,7 +611,7 @@ + if (strlen(sd->digest_str) == func->digest_len * 2) { + /* Convert the command digest from ascii hex to binary. */ + for (i = 0; i < func->digest_len; i++) { +- h = hexchar(&sd->digest_str[i + i]); ++ const int h = hexchar(&sd->digest_str[i + i]); + if (h == -1) + goto bad_format; + sudoers_digest[i] = (unsigned char)h; +@@ -633,6 +635,12 @@ + + func->init(&ctx); + while ((nread = fread(buf, 1, sizeof(buf), fp)) != 0) { ++ /* Check for #! cookie and set is_script. */ ++ if (first) { ++ first = false; ++ if (nread >= 2 && buf[0] == '#' && buf[1] == '!') ++ is_script = true; ++ } + func->update(&ctx, buf, nread); + } + if (ferror(fp)) { +@@ -640,15 +648,36 @@ + fclose(fp); + debug_return_bool(false); + } +- fclose(fp); + func->final(file_digest, &ctx); + +- if (memcmp(file_digest, sudoers_digest, func->digest_len) == 0) +- debug_return_bool(true); +- sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO, +- "%s digest mismatch for %s, expecting %s", +- func->digest_name, file, sd->digest_str); +- debug_return_bool(false); ++ if (memcmp(file_digest, sudoers_digest, func->digest_len) != 0) { ++ fclose(fp); ++ sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO, ++ "%s digest mismatch for %s, expecting %s", ++ func->digest_name, file, sd->digest_str); ++ debug_return_bool(false); ++ } ++ ++#ifdef HAVE_FEXECVE ++ /* ++ * On systems with fexecve(2) we can use that to execute the ++ * matching command even when the directory is writable. ++ */ ++ if ((*fd = dup(fileno(fp))) == -1) { ++ sudo_debug_printf(SUDO_DEBUG_INFO, "unable to dup %s: %s", ++ file, strerror(errno)); ++ fclose(fp); ++ debug_return_bool(false); ++ } ++ /* ++ * Shell scripts go through namei twice and so we can't set the close ++ * on exec flag on the fd for fexecve(2). ++ */ ++ if (!is_script) ++ fcntl(*fd, F_SETFD, FD_CLOEXEC); ++#endif /* HAVE_FEXECVE */ ++ fclose(fp); ++ debug_return_bool(true); + bad_format: + sudo_warnx(U_("digest for %s (%s) is not in %s form"), file, + sd->digest_str, func->digest_name); +@@ -690,7 +719,11 @@ + debug_return_bool(false); + if (!command_args_match(sudoers_cmnd, sudoers_args)) + debug_return_bool(false); +- if (digest != NULL && !digest_matches(sudoers_cmnd, digest)) { ++ if (cmnd_fd != -1) { ++ close(cmnd_fd); ++ cmnd_fd = -1; ++ } ++ if (digest != NULL && !digest_matches(sudoers_cmnd, digest, &cmnd_fd)) { + /* XXX - log functions not available but we should log very loudly */ + debug_return_bool(false); + } +diff -ruN a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c +--- a/plugins/sudoers/policy.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/plugins/sudoers/policy.c 2016-08-08 12:56:03.457680623 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2010-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -371,6 +371,9 @@ + user_umask = umask(SUDO_UMASK); + umask(user_umask); + ++ /* Some systems support fexecve() which we use for digest matches. */ ++ cmnd_fd = -1; ++ + /* Dump settings and user info (XXX - plugin args) */ + for (cur = info->settings; *cur != NULL; cur++) + sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur); +@@ -545,6 +548,16 @@ + if (asprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask) == -1) + goto oom; + } ++ if (cmnd_fd != -1) { ++ if (sudo_version < SUDO_API_MKVERSION(1, 9)) { ++ /* execfd only supported by plugin API 1.9 and higher */ ++ close(cmnd_fd); ++ cmnd_fd = -1; ++ } else { ++ if (asprintf(&command_info[info_len++], "execfd=%d", cmnd_fd) == -1) ++ goto oom; ++ } ++ } + #ifdef HAVE_LOGIN_CAP_H + if (def_use_loginclass) { + if ((command_info[info_len++] = sudo_new_key_val("login_class", login_class)) == NULL) +diff -ruN a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h +--- a/plugins/sudoers/sudoers.h 2016-08-08 12:55:08.781888802 +0200 ++++ b/plugins/sudoers/sudoers.h 2016-08-08 12:56:03.457680623 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1993-1996, 1998-2005, 2007-2015 ++ * Copyright (c) 1993-1996, 1998-2005, 2007-2016 + * Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any +@@ -90,6 +90,7 @@ + const char *cwd; + char *iolog_file; + GETGROUPS_T *gids; ++ int execfd; + int ngids; + int closefrom; + int lines; +@@ -197,6 +198,7 @@ + #define user_srunhost (sudo_user.srunhost) + #define user_ccname (sudo_user.krb5_ccname) + #define safe_cmnd (sudo_user.cmnd_safe) ++#define cmnd_fd (sudo_user.execfd) + #define login_class (sudo_user.class_name) + #define runas_pw (sudo_user._runas_pw) + #define runas_gr (sudo_user._runas_gr) +diff -ruN a/src/exec.c b/src/exec.c +--- a/src/exec.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/exec.c 2016-08-08 12:56:03.457680623 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -176,13 +176,13 @@ + } + #ifdef HAVE_SELINUX + if (ISSET(details->flags, CD_RBAC_ENABLED)) { +- selinux_execve(details->command, details->argv, details->envp, +- ISSET(details->flags, CD_NOEXEC)); ++ selinux_execve(details->execfd, details->command, details->argv, ++ details->envp, ISSET(details->flags, CD_NOEXEC)); + } else + #endif + { +- sudo_execve(details->command, details->argv, details->envp, +- ISSET(details->flags, CD_NOEXEC)); ++ sudo_execve(details->execfd, details->command, details->argv, ++ details->envp, ISSET(details->flags, CD_NOEXEC)); + } + } + cstat->type = CMD_ERRNO; +diff -ruN a/src/exec_common.c b/src/exec_common.c +--- a/src/exec_common.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/exec_common.c 2016-08-08 12:56:03.457680623 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -134,14 +134,19 @@ + * ala execvp(3) if we get ENOEXEC. + */ + int +-sudo_execve(const char *path, char *const argv[], char *const envp[], bool noexec) ++sudo_execve(int fd, const char *path, char *const argv[], char *const envp[], bool noexec) + { + /* Modify the environment as needed to disable further execve(). */ + if (noexec) + envp = disable_execute(envp); + +- execve(path, argv, envp); +- if (errno == ENOEXEC) { ++#ifdef HAVE_FEXECVE ++ if (fd != -1) ++ fexecve(fd, argv, envp); ++ else ++#endif ++ execve(path, argv, envp); ++ if (fd == -1 && errno == ENOEXEC) { + int argc; + char **nargv; + +diff -ruN a/src/selinux.c b/src/selinux.c +--- a/src/selinux.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/selinux.c 2016-08-08 12:56:03.461680315 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com> + * + * Borrowed heavily from newrole source code +@@ -373,7 +373,7 @@ + } + + void +-selinux_execve(const char *path, char *const argv[], char *const envp[], ++selinux_execve(int fd, const char *path, char *const argv[], char *const envp[], + int noexec) + { + char **nargv; +@@ -409,6 +409,8 @@ + */ + for (argc = 0; argv[argc] != NULL; argc++) + continue; ++ if (fd != -1) ++ argc++; + nargv = reallocarray(NULL, argc + 2, sizeof(char *)); + if (nargv == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +@@ -418,11 +420,16 @@ + nargv[0] = *argv[0] == '-' ? "-sesh-noexec" : "sesh-noexec"; + else + nargv[0] = *argv[0] == '-' ? "-sesh" : "sesh"; +- nargv[1] = (char *)path; +- memcpy(&nargv[2], &argv[1], argc * sizeof(char *)); /* copies NULL */ ++ argc = 1; ++ if (fd != -1 && asprintf(&nargv[argc++], "--execfd=%d", fd) == -1) { ++ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); ++ debug_return; ++ } ++ nargv[argc] = (char *)path; ++ memcpy(&nargv[argc + 1], &argv[argc], argc * sizeof(char *)); /* copies NULL */ + + /* sesh will handle noexec for us. */ +- sudo_execve(sesh, nargv, envp, false); ++ sudo_execve(-1, sesh, nargv, envp, false); + serrno = errno; + free(nargv); + errno = serrno; +diff -ruN a/src/sesh.c b/src/sesh.c +--- a/src/sesh.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/sesh.c 2016-08-08 12:56:03.461680315 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2008, 2010-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2008, 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -87,6 +87,7 @@ + } else { + bool login_shell, noexec = false; + char *cp, *cmnd; ++ int fd = -1; + + /* If the first char of argv[0] is '-', we are running a login shell. */ + login_shell = argv[0][0] == '-'; +@@ -95,6 +96,18 @@ + if ((cp = strrchr(argv[0], '-')) != NULL && cp != argv[0]) + noexec = strcmp(cp, "-noexec") == 0; + ++ /* If argv[1] is --execfd=%d, extract the fd to exec with. */ ++ if (strncmp(argv[1], "--execfd=", 9) == 0) { ++ const char *errstr; ++ ++ cp = argv[1] + 9; ++ fd = strtonum(cp, 0, INT_MAX, &errstr); ++ if (errstr != NULL) ++ sudo_fatalx(U_("invalid file descriptor number: %s"), cp); ++ argv++; ++ argc--; ++ } ++ + /* Shift argv and make a copy of the command to execute. */ + argv++; + argc--; +@@ -108,7 +121,7 @@ + *cp = '-'; + argv[0] = cp; + } +- sudo_execve(cmnd, argv, envp, noexec); ++ sudo_execve(fd, cmnd, argv, envp, noexec); + sudo_warn(U_("unable to execute %s"), cmnd); + ret = SESH_ERR_FAILURE; + } +diff -ruN a/src/sudo.c b/src/sudo.c +--- a/src/sudo.c 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/sudo.c 2016-08-08 12:56:03.461680315 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -585,6 +585,7 @@ + + memset(details, 0, sizeof(*details)); + details->closefrom = -1; ++ details->execfd = -1; + TAILQ_INIT(&details->preserved_fds); + + #define SET_STRING(s, n) \ +@@ -615,6 +616,21 @@ + SET(details->flags, CD_EXEC_BG); + break; + } ++ if (strncmp("execfd=", info[i], sizeof("execfd=") - 1) == 0) { ++ cp = info[i] + sizeof("execfd=") - 1; ++ details->execfd = strtonum(cp, 0, INT_MAX, &errstr); ++ if (errstr != NULL) ++ sudo_fatalx(U_("%s: %s"), info[i], U_(errstr)); ++#ifdef HAVE_FEXECVE ++ /* Must keep fd open during exec. */ ++ add_preserved_fd(&details->preserved_fds, details->execfd); ++#else ++ /* Plugin thinks we support fexecve() but we don't. */ ++ fcntl(details->execfd, F_SETFD, FD_CLOEXEC); ++ details->execfd = -1; ++#endif ++ break; ++ } + break; + case 'l': + SET_STRING("login_class=", login_class) +diff -ruN a/src/sudo_exec.h b/src/sudo_exec.h +--- a/src/sudo_exec.h 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/sudo_exec.h 2016-08-08 13:04:19.127533565 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2010-2013 Todd C. Miller <Todd.Miller@courtesan.com> ++ * Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -74,7 +74,7 @@ + + /* exec.c */ + struct sudo_event_base; +-int sudo_execve(const char *path, char *const argv[], char *const envp[], bool noexec); ++int sudo_execve(int fd, const char *path, char *const argv[], char *const envp[], bool noexec); + extern volatile pid_t cmnd_pid; + + /* exec_pty.c */ +diff -ruN a/src/sudo.h b/src/sudo.h +--- a/src/sudo.h 2016-08-08 12:55:08.781888802 +0200 ++++ b/src/sudo.h 2016-08-08 12:56:03.465680007 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1993-1996, 1998-2005, 2007-2014 ++ * Copyright (c) 1993-1996, 1998-2005, 2007-2016 + * Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any +@@ -149,6 +149,7 @@ + int ngroups; + int closefrom; + int flags; ++ int execfd; + struct preserved_fd_list preserved_fds; + struct passwd *pw; + GETGROUPS_T *groups; +@@ -221,7 +222,7 @@ + int selinux_restore_tty(void); + int selinux_setup(const char *role, const char *type, const char *ttyn, + int ttyfd); +-void selinux_execve(const char *path, char *const argv[], char *const envp[], ++void selinux_execve(int fd, const char *path, char *const argv[], char *envp[], + int noexec); + + /* solaris.c */ |