From: Todd C. Miller Date: Mon, 4 Jan 2016 17:35:18 +0000 (-0700) Subject: Add support for using fexecve() if supported on commands that are X-Git-Tag: SUDO_1_8_16^2~84 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b20977d4452adc95de4fb582ed688335639e6dc3;p=sudo Add support for using fexecve() if supported on commands that are checksummed. --- diff --git a/configure b/configure index 8e1d62568..de475d93f 100755 --- a/configure +++ b/configure @@ -2650,6 +2650,7 @@ as_fn_append ac_header_list " sys/bsdtypes.h" 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 @@ done + + for ac_func in getgrouplist do : ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist" @@ -19903,8 +19906,8 @@ _ACEOF 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 --git a/configure.ac b/configure.ac index 59cf10252..481433c68 100644 --- a/configure.ac +++ b/configure.ac @@ -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 +dnl Copyright (c) 1994-1996,1998-2016 Todd C. Miller dnl AC_PREREQ([2.59]) AC_INIT([sudo], [1.8.16], [https://bugzilla.sudo.ws/], [sudo]) @@ -2384,7 +2384,7 @@ dnl 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 @@ dnl 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 --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index 8db3ca4ab..d04e4171d 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -499,6 +499,11 @@ DDEESSCCRRIIPPTTIIOONN 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 @@ PPLLUUGGIINN AAPPII CCHHAANNGGEELLOOGG 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) @@ -1534,4 +1542,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.16 November 20, 2015 Sudo 1.8.16 +Sudo 1.8.16 January 4, 2016 Sudo 1.8.16 diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 0ad191df1..bf14f56f1 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -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 +.\" Copyright (c) 2009-2016 Todd C. Miller .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -16,7 +16,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.TH "SUDO_PLUGIN" "5" "November 20, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDO_PLUGIN" "5" "January 4, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -881,6 +881,17 @@ This setting has no effect unless I/O logging is enabled or \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 @@ The 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 --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in index ab3e0f5af..9f9250d0c 100644 --- a/doc/sudo_plugin.mdoc.in +++ b/doc/sudo_plugin.mdoc.in @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 2009-2015 Todd C. Miller +.\" Copyright (c) 2009-2016 Todd C. Miller .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 20, 2015 +.Dd January 4, 2016 .Dt SUDO_PLUGIN @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -784,6 +784,16 @@ be a way to enabled or disable it on a per-command basis. 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 @@ The 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 --git a/doc/sudoers.cat b/doc/sudoers.cat index 273248c5d..31ecc0a69 100644 --- a/doc/sudoers.cat +++ b/doc/sudoers.cat @@ -408,10 +408,12 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT $ openssl dgst -binary -sha224 /bin/ls | openssl base64 EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ== - If the user has write access to either the command itself or the - directory in which the command is located (directly or via a ssuuddoo - 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. + Warning, if the user has write access to the command itself (directly or + via a ssuuddoo 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. @@ -2493,4 +2495,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.16 December 11, 2015 Sudo 1.8.16 +Sudo 1.8.16 January 4, 2015 Sudo 1.8.16 diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index a195a5a7e..7875060d0 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -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 .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -21,7 +21,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.TH "SUDOERS" "5" "December 11, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "5" "January 4, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -874,12 +874,14 @@ EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ== .RE .fi .PP -If the user has write access to either the command itself or the -directory in which the command is located (directly or via a +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. +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" diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 3c608363a..307428a25 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 1994-1996, 1998-2005, 2007-2015 +.\" Copyright (c) 1994-1996, 1998-2005, 2007-2016 .\" Todd C. Miller .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -19,7 +19,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.Dd December 11, 2015 +.Dd January 4, 2015 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -831,12 +831,14 @@ $ openssl dgst -binary -sha224 /bin/ls | openssl base64 EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ== .Ed .Pp -If the user has write access to either the command itself or the -directory in which the command is located (directly or via a +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. +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 diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index ed08c255f..e00b54f43 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Todd C. Miller + * Copyright (c) 2009-2016 Todd C. Miller * * 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 --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index f0e954ed2..460ac2d80 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2015 + * Copyright (c) 1996, 1998-2005, 2007-2016 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -55,6 +55,7 @@ # include #endif /* HAVE_NETGROUP_H */ #include +#include #include #include #include @@ -583,17 +584,18 @@ static struct digest_function { }; 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 @@ digest_matches(const char *file, const struct sudo_digest *sd) 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 @@ digest_matches(const char *file, const struct sudo_digest *sd) 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 @@ digest_matches(const char *file, const struct sudo_digest *sd) 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 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const 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 --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index 8db08908b..ff5392b04 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Todd C. Miller + * Copyright (c) 2010-2016 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -377,6 +377,9 @@ sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group) 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); @@ -551,6 +554,16 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask, 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 --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 438eadb81..6d4769688 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1993-1996, 1998-2005, 2007-2015 + * Copyright (c) 1993-1996, 1998-2005, 2007-2016 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -90,6 +90,7 @@ struct sudo_user { const char *cwd; char *iolog_file; GETGROUPS_T *gids; + int execfd; int ngids; int closefrom; int lines; @@ -197,6 +198,7 @@ struct sudo_user { #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 --git a/src/exec.c b/src/exec.c index aeedf8dc2..1ceb99bb5 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Todd C. Miller + * Copyright (c) 2009-2016 Todd C. Miller * * 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 @@ exec_cmnd(struct command_details *details, struct command_status *cstat, } #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 --git a/src/exec_common.c b/src/exec_common.c index 20b5df6c7..bb4460f76 100644 --- a/src/exec_common.c +++ b/src/exec_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Todd C. Miller + * Copyright (c) 2009-2016 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -179,14 +179,19 @@ disable_execute(char *envp[]) * ala execvp(3) if we get ENOEXEC. */ int -sudo_execve(const char *path, char *const argv[], char *envp[], bool noexec) +sudo_execve(int fd, const char *path, char *const argv[], char *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 --git a/src/selinux.c b/src/selinux.c index 3d5a58d69..dd30f29a2 100644 --- a/src/selinux.c +++ b/src/selinux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Todd C. Miller + * Copyright (c) 2009-2016 Todd C. Miller * Copyright (c) 2008 Dan Walsh * * Borrowed heavily from newrole source code @@ -373,7 +373,7 @@ done: } void -selinux_execve(const char *path, char *const argv[], char *const envp[], +selinux_execve(int fd, const char *path, char *const argv[], char *envp[], bool noexec) { char **nargv; @@ -409,6 +409,8 @@ selinux_execve(const char *path, char *const argv[], char *const envp[], */ 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 @@ selinux_execve(const char *path, char *const argv[], char *const envp[], 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 --git a/src/sesh.c b/src/sesh.c index dbf2dcdc0..c07366d15 100644 --- a/src/sesh.c +++ b/src/sesh.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010-2015 Todd C. Miller + * Copyright (c) 2008, 2010-2016 Todd C. Miller * * 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 @@ main(int argc, char *argv[], char *envp[]) } 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 @@ main(int argc, char *argv[], char *envp[]) 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 @@ main(int argc, char *argv[], char *envp[]) *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 --git a/src/sudo.c b/src/sudo.c index 578642bea..50f72ff92 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015 Todd C. Miller + * Copyright (c) 2009-2016 Todd C. Miller * * 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 @@ command_info_to_details(char * const info[], struct command_details *details) 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 @@ command_info_to_details(char * const info[], struct command_details *details) 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 --git a/src/sudo.h b/src/sudo.h index 8f29ae81b..32987f30c 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1993-1996, 1998-2005, 2007-2014 + * Copyright (c) 1993-1996, 1998-2005, 2007-2016 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -149,6 +149,7 @@ struct command_details { int ngroups; int closefrom; int flags; + int execfd; struct preserved_fd_list preserved_fds; struct passwd *pw; GETGROUPS_T *groups; @@ -221,8 +222,8 @@ int os_init_openbsd(int argc, char *argv[], char *envp[]); 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[], - bool noexec); +void selinux_execve(int fd, const char *path, char *const argv[], + char *envp[], bool noexec); /* solaris.c */ void set_project(struct passwd *); diff --git a/src/sudo_exec.h b/src/sudo_exec.h index a2c0ab035..0099cb09d 100644 --- a/src/sudo_exec.h +++ b/src/sudo_exec.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Todd C. Miller + * Copyright (c) 2010-2016 Todd C. Miller * * 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 *envp[], bool noexec); +int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], bool noexec); extern volatile pid_t cmnd_pid; /* exec_pty.c */