From 3ce19efca958e607ab5a24fea3baf3adfbc4aac6 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 29 Jul 2022 15:22:27 -0600 Subject: [PATCH] Add intercept_verify sudoers option to control execve(2) argument checking. --- docs/sudoers.man.in | 27 +++++++++++++++++++- docs/sudoers.mdoc.in | 26 +++++++++++++++++++- plugins/sudoers/def_data.c | 4 +++ plugins/sudoers/def_data.h | 4 ++- plugins/sudoers/def_data.in | 3 +++ plugins/sudoers/defaults.c | 1 + plugins/sudoers/policy.c | 6 ++++- src/exec_ptrace.c | 10 +++++--- src/sudo.c | 1 + src/sudo.h | 49 +++++++++++++++++++------------------ 10 files changed, 99 insertions(+), 32 deletions(-) diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in index 5f73f7ca2..fadc62382 100644 --- a/docs/sudoers.man.in +++ b/docs/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "May 31, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "July 29, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -3399,6 +3399,31 @@ by default. .sp This setting is only supported by version 1.9.8 or higher. .TP 18n +intercept_verify +If set, +\fBsudo\fR +will attempt to verify that a command run in intercept mode has +the expected path name and command line arguments. +The process is stopped after +execve(2) +has completed but before the new command has had a chance to run. +In the case of a path name or argument mismatch, the command will be sent a +\fRSIGKILL\fR +signal and terminated. +This flag has no effect unless the +\fIintercept\fR +flag is enabled or the +\fIINTERCEPT\fR +tag has been set for the command and the +\fIintercept_type\fR +option is set to +\fItrace\fR. +This flag is +\fIon\fR +by default. +.sp +This setting is only supported by version 1.9.12 or higher. +.TP 18n netgroup_tuple If set, netgroup lookups will be performed using the full netgroup tuple: host name, user name, and domain (if one is set). diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in index 29aeacfdd..f4987d8ea 100644 --- a/docs/sudoers.mdoc.in +++ b/docs/sudoers.mdoc.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd May 31, 2022 +.Dd July 29, 2022 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -3220,6 +3220,30 @@ This flag is by default. .Pp This setting is only supported by version 1.9.8 or higher. +.It intercept_verify +If set, +.Nm sudo +will attempt to verify that a command run in intercept mode has +the expected path name and command line arguments. +The process is stopped after +.Xr execve 2 +has completed but before the new command has had a chance to run. +In the case of a path name or argument mismatch, the command will be sent a +.Dv SIGKILL +signal and terminated. +This flag has no effect unless the +.Em intercept +flag is enabled or the +.Em INTERCEPT +tag has been set for the command and the +.Em intercept_type +option is set to +.Em trace . +This flag is +.Em on +by default. +.Pp +This setting is only supported by version 1.9.12 or higher. .It netgroup_tuple If set, netgroup lookups will be performed using the full netgroup tuple: host name, user name, and domain (if one is set). diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 41de8fc0b..54b20356e 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -667,6 +667,10 @@ struct sudo_defs_types sudo_defs_table[] = { "intercept_type", T_TUPLE, N_("The mechanism used by the intercept and log_subcmds options: %s"), def_data_intercept_type, + }, { + "intercept_verify", T_FLAG, + N_("Whether to verify the command and arguments after execution"), + NULL, }, { "apparmor_profile", T_STR, N_("AppArmor profile to use in the new security context: %s"), diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index 38de4386b..4d8d36bfc 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -308,7 +308,9 @@ #define def_passprompt_regex (sudo_defs_table[I_PASSPROMPT_REGEX].sd_un.list) #define I_INTERCEPT_TYPE 153 #define def_intercept_type (sudo_defs_table[I_INTERCEPT_TYPE].sd_un.tuple) -#define I_APPARMOR_PROFILE 154 +#define I_INTERCEPT_VERIFY 154 +#define def_intercept_verify (sudo_defs_table[I_INTERCEPT_VERIFY].sd_un.flag) +#define I_APPARMOR_PROFILE 155 #define def_apparmor_profile (sudo_defs_table[I_APPARMOR_PROFILE].sd_un.str) enum def_tuple { diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index c24d6706c..645dae6a6 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -479,6 +479,9 @@ intercept_type T_TUPLE "The mechanism used by the intercept and log_subcmds options: %s" dso trace +intercept_verify + T_FLAG + "Whether to verify the command and arguments after execution" apparmor_profile T_STR "AppArmor profile to use in the new security context: %s" diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 9b8c6a76b..1c993c2d5 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -549,6 +549,7 @@ init_defaults(void) if ((def_rlimit_core = strdup("0,0")) == NULL) goto oom; def_intercept_type = dso; + def_intercept_verify = true; def_netgroup_tuple = false; def_sudoedit_checkdir = true; def_iolog_mode = S_IRUSR|S_IWUSR; diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index 5a0852f4d..fe2c20d73 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -636,7 +636,7 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[], } /* Increase the length of command_info as needed, it is *not* checked. */ - command_info = calloc(71, sizeof(char *)); + command_info = calloc(72, sizeof(char *)); if (command_info == NULL) goto oom; @@ -812,6 +812,10 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[], if ((command_info[info_len++] = strdup("use_ptrace=true")) == NULL) goto oom; } + if (def_intercept_verify) { + if ((command_info[info_len++] = strdup("intercept_verify=true")) == NULL) + goto oom; + } if (def_noexec) { if ((command_info[info_len++] = strdup("noexec=true")) == NULL) goto oom; diff --git a/src/exec_ptrace.c b/src/exec_ptrace.c index 0f7231ae2..310a2f3c6 100644 --- a/src/exec_ptrace.c +++ b/src/exec_ptrace.c @@ -1532,10 +1532,12 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure) } } if (closure->state == POLICY_ACCEPT) { - /* Verify execve(2) args post-exec. */ - if (!ptrace_verify_post_exec(pid, ®s, closure)) { - if (errno != ESRCH) - kill(pid, SIGKILL); + if (ISSET(closure->details->flags, CD_INTERCEPT_VERIFY)) { + /* Verify execve(2) args post-exec. */ + if (!ptrace_verify_post_exec(pid, ®s, closure)) { + if (errno != ESRCH) + kill(pid, SIGKILL); + } } } break; diff --git a/src/sudo.c b/src/sudo.c index 7e26b869c..f66318dc3 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -734,6 +734,7 @@ command_info_to_details(char * const info[], struct command_details *details) break; case 'i': SET_FLAG("intercept=", CD_INTERCEPT) + SET_FLAG("intercept_verify=", CD_INTERCEPT_VERIFY) break; case 'l': SET_STRING("login_class=", login_class) diff --git a/src/sudo.h b/src/sudo.h index 756c8db3a..29628885f 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -149,30 +149,31 @@ struct user_details { int ts_cols; }; -#define CD_SET_UID 0x000001 -#define CD_SET_EUID 0x000002 -#define CD_SET_GID 0x000004 -#define CD_SET_EGID 0x000008 -#define CD_PRESERVE_GROUPS 0x000010 -#define CD_INTERCEPT 0x000020 -#define CD_NOEXEC 0x000040 -#define CD_SET_PRIORITY 0x000080 -#define CD_SET_UMASK 0x000100 -#define CD_SET_TIMEOUT 0x000200 -#define CD_SUDOEDIT 0x000400 -#define CD_BACKGROUND 0x000800 -#define CD_RBAC_ENABLED 0x001000 -#define CD_USE_PTY 0x002000 -#define CD_SET_UTMP 0x004000 -#define CD_EXEC_BG 0x008000 -#define CD_SUDOEDIT_FOLLOW 0x010000 -#define CD_SUDOEDIT_CHECKDIR 0x020000 -#define CD_SET_GROUPS 0x040000 -#define CD_LOGIN_SHELL 0x080000 -#define CD_OVERRIDE_UMASK 0x100000 -#define CD_LOG_SUBCMDS 0x200000 -#define CD_USE_PTRACE 0x400000 -#define CD_FEXECVE 0x800000 +#define CD_SET_UID 0x00000001 +#define CD_SET_EUID 0x00000002 +#define CD_SET_GID 0x00000004 +#define CD_SET_EGID 0x00000008 +#define CD_PRESERVE_GROUPS 0x00000010 +#define CD_INTERCEPT 0x00000020 +#define CD_NOEXEC 0x00000040 +#define CD_SET_PRIORITY 0x00000080 +#define CD_SET_UMASK 0x00000100 +#define CD_SET_TIMEOUT 0x00000200 +#define CD_SUDOEDIT 0x00000400 +#define CD_BACKGROUND 0x00000800 +#define CD_RBAC_ENABLED 0x00001000 +#define CD_USE_PTY 0x00002000 +#define CD_SET_UTMP 0x00004000 +#define CD_EXEC_BG 0x00008000 +#define CD_SUDOEDIT_FOLLOW 0x00010000 +#define CD_SUDOEDIT_CHECKDIR 0x00020000 +#define CD_SET_GROUPS 0x00040000 +#define CD_LOGIN_SHELL 0x00080000 +#define CD_OVERRIDE_UMASK 0x00100000 +#define CD_LOG_SUBCMDS 0x00200000 +#define CD_USE_PTRACE 0x00400000 +#define CD_FEXECVE 0x00800000 +#define CD_INTERCEPT_VERIFY 0x01000000 struct preserved_fd { TAILQ_ENTRY(preserved_fd) entries;