]> granicus.if.org Git - sudo/commitdiff
Add support for using fexecve() if supported on commands that are
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 4 Jan 2016 17:35:18 +0000 (10:35 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 4 Jan 2016 17:35:18 +0000 (10:35 -0700)
checksummed.

19 files changed:
configure
configure.ac
doc/sudo_plugin.cat
doc/sudo_plugin.man.in
doc/sudo_plugin.mdoc.in
doc/sudoers.cat
doc/sudoers.man.in
doc/sudoers.mdoc.in
include/sudo_plugin.h
plugins/sudoers/match.c
plugins/sudoers/policy.c
plugins/sudoers/sudoers.h
src/exec.c
src/exec_common.c
src/selinux.c
src/sesh.c
src/sudo.c
src/sudo.h
src/sudo_exec.h

index 8e1d625685d994e3a0911f0571653f96376423c7..de475d93ff4dca926b2a937f54ef203f3d4366e5 100755 (executable)
--- 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"
index 59cf1025205cff59124f7d2ffdf6ce15415e08fa..481433c6878896313958eb835eece07051876a89 100644 (file)
@@ -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.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
index 8db3ca4abe78c7707150be24e34c08bce1e00e52..d04e4171d01ef3e2c98d6d010a1cbd99fd4b513f 100644 (file)
@@ -499,6 +499,11 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                        This setting has no effect unless I/O logging is
                        enabled or _\bu_\bs_\be_\b__\bp_\bt_\by is enabled.
 
+                 execfd=number
+                       If specified, s\bsu\bud\bdo\bo will use the fexecve(2) system call
+                       to execute the command instead of execve(2).  The
+                       specified _\bn_\bu_\bm_\bb_\be_\br 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 @@ P\bPL\bLU\bUG\bGI\bIN\bN A\bAP\bPI\bI C\bCH\bHA\bAN\bNG\bGE\bEL\bLO\bOG\bG
            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 _\be_\bx_\be_\bc_\bf_\bd entry was added to the command_info list.
+
 S\bSE\bEE\bE A\bAL\bLS\bSO\bO
      sudo.conf(4), sudoers(4), sudo(1m)
 
@@ -1534,4 +1542,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo 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
index 0ad191df1d678173e9fdf02146881293f900af9e..bf14f56f113e700b8cec45aae84383c1b760e48b 100644 (file)
@@ -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
@@ -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@),
index ab3e0f5afab3e64b8f6ec75af8e8da4ce80d5121..9f9250d0cd42704f2914c03869e98ae6dda96117 100644 (file)
@@ -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
@@ -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@ ,
index 273248c5d4609c33d9910cb49a1fc113cba1ae5d..31ecc0a690dcbe6fdacaf462f2633c9d3ea107e6 100644 (file)
@@ -408,10 +408,12 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS F\bFI\bIL\bLE\bE F\bFO\bOR\bRM\bMA\bAT\bT
      $ 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 s\bsu\bud\bdo\bo
-     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 s\bsu\bud\bdo\bo 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 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo 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
index a195a5a7ed61a1447cb672d2307a82fe4a011151..7875060d01591ed06f9c675bdc00d97825c1a257 100644 (file)
@@ -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
@@ -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"
index 3c608363ae7d0778f1163a1c3396afd6f22f47d2..307428a2580c7a3b6dd48ab37d3ce8dca54912b1 100644 (file)
@@ -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
@@ -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
index ed08c255f97828c6f103cb573fba206dbdf63eb2..e00b54f432a98225f22155a9168019fd8830fc48 100644 (file)
@@ -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)
 
index f0e954ed23cd6aa6d181cba0c44a66eb6b637c42..460ac2d80139d28e0ce9a0e7e6a2dc8a917d26b0 100644 (file)
@@ -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 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);
     }
index 8db08908bca92edb9690b58255844c4a89455c5b..ff5392b0470eace47aba8d3ba8526b7578267d94 100644 (file)
@@ -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
@@ -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)
index 438eadb8185226dde8f91b85e65a9924ed8295b5..6d4769688547fc68cdb61ae64fa46b259a6b4167 100644 (file)
@@ -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 @@ 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)
index aeedf8dc26cc022a91a24a0b801214dee3443ea6..1ceb99bb5ce468bb33932f66cbf586d2901e565c 100644 (file)
@@ -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 @@ 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;
index 20b5df6c7121b523025337b245799d6d47f438e2..bb4460f76860b0db2de12f11f91626a05fd73e94 100644 (file)
@@ -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
@@ -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;
 
index 3d5a58d69b405bfd5bff746c7b716311f789f05b..dd30f29a27859a28575d189c0a145383f1360d82 100644 (file)
@@ -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 @@ 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;
index dbf2dcdc0eacd619711c49504b94de7364f3e3e8..c07366d159165824dd31b340d88c8837ee550162 100644 (file)
@@ -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 @@ 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;
     }
index 578642beab4620aa4bccb4d29e4059920e0c687f..50f72ff928861b126e9b845a1a049515da96af65 100644 (file)
@@ -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 @@ 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)
index 8f29ae81b682e463a56bb36f03bd5da29387423a..32987f30c1e74c02e5cbe4d71bf6019fddcdf01d 100644 (file)
@@ -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 @@ 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 *);
index a2c0ab035a14984c39afbe99da01e010e8cac6ee..0099cb09d12cfadc52042c2ac75fbad278ab0e78 100644 (file)
@@ -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 *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 */