From 9b1f0f16bfe7552810b4adb6b17ac3674da660f9 Mon Sep 17 00:00:00 2001 From: Tomas Sykora 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