Blob Blame History Raw
From 9b1f0f16bfe7552810b4adb6b17ac3674da660f9 Mon Sep 17 00:00:00 2001
From: Tomas Sykora <tosykora@redhat.com>
Date: Mon, 15 Aug 2016 15:13:31 +0200
Subject: [PATCH] Backport direct exec of command from sudo

Added cmnd_no_wait option
Sudo does not run command in a new child process,
when cmnd_no_wait is enabled.

!!!
Upstream can do that too now in 1.8.17 with combination of
pam_session, pam_setcred and use_pty option.
They must be disabled and I/O logging must not be configured.
See "man sudoers".

rebased from:
Patch8: sudo-1.8.6p3-nowaitopt.patch

Resolves:
rhbz#840980
---
 plugins/sudoers/def_data.c  |  4 ++++
 plugins/sudoers/def_data.h  |  2 ++
 plugins/sudoers/def_data.in |  3 +++
 plugins/sudoers/policy.c    |  4 ++++
 src/exec.c                  | 34 ++++++++++++++++++++++++++++++++++
 src/sudo.c                  |  5 +++++
 src/sudo.h                  |  1 +
 7 files changed, 53 insertions(+)

diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
index 00caa8b..d8b1ada 100644
--- a/plugins/sudoers/def_data.c
+++ b/plugins/sudoers/def_data.c
@@ -435,6 +435,10 @@ struct sudo_defs_types sudo_defs_table[] = {
 	N_("File mode to use for the I/O log files: 0%o"),
 	NULL,
     }, {
+	"cmnd_no_wait", T_FLAG,
+	N_("Don't fork and wait for the command to finish, just exec it"),
+	NULL,
+    }, {
 	NULL, 0, NULL
     }
 };
diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
index d83d2c3..1b6be3d 100644
--- a/plugins/sudoers/def_data.h
+++ b/plugins/sudoers/def_data.h
@@ -204,6 +204,8 @@
 #define def_iolog_group         (sudo_defs_table[I_IOLOG_GROUP].sd_un.str)
 #define I_IOLOG_MODE            102
 #define def_iolog_mode          (sudo_defs_table[I_IOLOG_MODE].sd_un.mode)
+#define I_CMND_NO_WAIT          103
+#define def_cmnd_no_wait        (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag)
 
 enum def_tuple {
 	never,
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
index 9f069f1..5200fe3 100644
--- a/plugins/sudoers/def_data.in
+++ b/plugins/sudoers/def_data.in
@@ -322,3 +322,6 @@ iolog_group
 iolog_mode
 	T_MODE
 	"File mode to use for the I/O log files: 0%o"
+cmnd_no_wait
+	T_FLAG
+	"Don't fork and wait for the command to finish, just exec it"
diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c
index 4ee1e28..93df1dd 100644
--- a/plugins/sudoers/policy.c
+++ b/plugins/sudoers/policy.c
@@ -564,6 +564,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
 	if ((command_info[info_len++] = strdup("use_pty=true")) == NULL)
 	    goto oom;
     }
+    if (def_cmnd_no_wait) {
+        if ((command_info[info_len++] = strdup("cmnd_no_wait=true")) == NULL)
+            goto oom;
+    }
     if (def_utmp_runas) {
 	if ((command_info[info_len++] = sudo_new_key_val("utmp_user", runas_pw->pw_name)) == NULL)
 	    goto oom;
diff --git a/src/exec.c b/src/exec.c
index 56da013..08bc86d 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -384,6 +384,41 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
     }
 
     /*
+     * If we don't want to wait for the command to exit, then just exec it.
+     * THIS WILL BREAK SEVERAL THINGS including SELinux, PAM sessions and I/O
+     * logging. Implemented because of rhbz#840980 (backwards compatibility).
+     * In 1.8.x branch this is even harder to get back, since the nowait code
+     * was completely removed.
+     */
+    if (details->flags & CD_DONTWAIT) {
+        if (exec_setup(details, NULL, -1) == true) {
+            restore_signals();
+            /* headed for execve() */
+            sudo_debug_execve(SUDO_DEBUG_INFO, details->command,
+                              details->argv, details->envp);
+            if (details->closefrom >= 0) {
+                closefrom(details->closefrom);
+            }
+#ifdef HAVE_SELINUX
+            if (ISSET(details->flags, CD_RBAC_ENABLED)) {
+                selinux_execve(-1, details->command, details->argv, details->envp,
+                               ISSET(details->flags, CD_NOEXEC));
+            } else
+#endif
+            {
+                sudo_execve(-1, details->command, details->argv, details->envp,
+                            ISSET(details->flags, CD_NOEXEC));
+            }
+            sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s",
+                              details->command, strerror(errno));
+        }
+        cstat->type = CMD_ERRNO;
+        cstat->val = errno;
+       return 127;
+    }
+
+
+    /*
      * We communicate with the child over a bi-directional pair of sockets.
      * Parent sends signal info to child and child sends back wait status.
      */
diff --git a/src/sudo.c b/src/sudo.c
index 5dd090d..0606a19 100644
--- a/src/sudo.c
+++ b/src/sudo.c
@@ -670,6 +670,11 @@ command_info_to_details(char * const info[], struct command_details *details)
 			sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
 		    break;
 		}
+		if (strncmp("cmnd_no_wait=", info[i], sizeof("cmnd_no_wait=") - 1) == 0) {
+                    if (sudo_strtobool(info[i] + sizeof("cmnd_no_wait=") - 1) == true)
+                        SET(details->flags, CD_DONTWAIT);
+                    break;
+                }
 		break;
 	    case 'e':
 		SET_FLAG("exec_background=", CD_EXEC_BG)
diff --git a/src/sudo.h b/src/sudo.h
index 3ac2c9d..f07ba11 100644
--- a/src/sudo.h
+++ b/src/sudo.h
@@ -130,6 +130,7 @@ struct user_details {
 #define CD_SUDOEDIT_FOLLOW	0x10000
 #define CD_SUDOEDIT_CHECKDIR	0x20000
 #define CD_SET_GROUPS		0x40000
+#define CD_DONTWAIT		0x80000
 
 struct preserved_fd {
     TAILQ_ENTRY(preserved_fd) entries;
-- 
2.7.4