From c7a7d319051b705b438c8db80a6968fa16bd7630 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 10 Mar 2011 14:24:10 -0500 Subject: [PATCH] Add support for disabling exec via solaris privileges. Includes preparation for moving noexec support out of sudoers and into front end as documented. --- config.h.in | 3 +++ configure | 11 +++++++++++ configure.in | 1 + plugins/sudoers/sudoers.c | 5 ++++- src/exec.c | 14 ++++++-------- src/exec_pty.c | 22 +++++++++------------- src/sudo.c | 21 +++++++++++++++++---- src/sudo.h | 10 +++++----- src/sudo_edit.c | 11 ++++++----- src/sudo_exec.h | 3 +-- 10 files changed, 63 insertions(+), 38 deletions(-) diff --git a/config.h.in b/config.h.in index 0b81e44da..68066a843 100644 --- a/config.h.in +++ b/config.h.in @@ -382,6 +382,9 @@ /* Define to 1 if you have the `posix_openpt' function. */ #undef HAVE_POSIX_OPENPT +/* Define to 1 if you have the `priv_set' function. */ +#undef HAVE_PRIV_SET + /* Define to 1 if you have the header file. */ #undef HAVE_PROJECT_H diff --git a/configure b/configure index e832f7943..f75e285d4 100755 --- a/configure +++ b/configure @@ -12974,6 +12974,17 @@ case "$host" in : ${mansectform='4'} : ${with_rpath='yes'} test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + for ac_func in priv_set +do : + ac_fn_c_check_func "$LINENO" "priv_set" "ac_cv_func_priv_set" +if test "x$ac_cv_func_priv_set" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PRIV_SET 1 +_ACEOF + +fi +done + ;; *-*-aix*) # To get all prototypes (so we pass -Wall) diff --git a/configure.in b/configure.in index 90f2da5cd..6d85742d6 100644 --- a/configure.in +++ b/configure.in @@ -1462,6 +1462,7 @@ case "$host" in : ${mansectform='4'} : ${with_rpath='yes'} test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + AC_CHECK_FUNCS(priv_set) ;; *-*-aix*) # To get all prototypes (so we pass -Wall) diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index a190da008..0a67f1ac7 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -433,7 +433,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], def_env_reset = FALSE; /* Build a new environment that avoids any nasty bits. */ - rebuild_env(def_noexec); + rebuild_env(def_noexec); /* XXX - move noexec bits */ /* Require a password if sudoers says so. */ if (def_authenticate) { @@ -533,6 +533,9 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], command_info[info_len++] = estrdup("iolog_compress=true"); } + if (def_noexec) + command_info[info_len++] = estrdup("noexec=true"); + log_allowed(validated); if (ISSET(sudo_mode, MODE_CHECK)) rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); diff --git a/src/exec.c b/src/exec.c index baa4e3f02..b1ea79b10 100644 --- a/src/exec.c +++ b/src/exec.c @@ -107,8 +107,7 @@ my_execve(const char *path, char *const argv[], char *const envp[]) * Fork and execute a command, returns the child's pid. * Sends errno back on sv[1] if execve() fails. */ -static int fork_cmnd(struct command_details *details, char *argv[], - char *envp[], int sv[2]) +static int fork_cmnd(struct command_details *details, int sv[2]) { struct command_status cstat; sigaction_t sa; @@ -138,10 +137,10 @@ static int fork_cmnd(struct command_details *details, char *argv[], closefrom(details->closefrom); #ifdef HAVE_SELINUX if (ISSET(details->flags, CD_RBAC_ENABLED)) - selinux_execve(details->command, argv, envp); + selinux_execve(details->command, details->argv, details->envp); else #endif - my_execve(details->command, argv, envp); + my_execve(details->command, details->argv, details->envp); } cstat.type = CMD_ERRNO; cstat.val = errno; @@ -201,8 +200,7 @@ restore_signals(void) * we fact that we have two different controlling terminals to deal with. */ int -sudo_execve(struct command_details *details, char *argv[], char *envp[], - struct command_status *cstat) +sudo_execve(struct command_details *details, struct command_status *cstat) { int maxfd, n, nready, sv[2], log_io = FALSE; fd_set *fdsr, *fdsw; @@ -279,9 +277,9 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[], * to and from pty. Adjusts maxfd as needed. */ if (log_io) - child = fork_pty(details, argv, envp, sv, &maxfd); + child = fork_pty(details, sv, &maxfd); else - child = fork_cmnd(details, argv, envp, sv); + child = fork_cmnd(details, sv); close(sv[1]); /* Set command timeout if specified. */ diff --git a/src/exec_pty.c b/src/exec_pty.c index be45d4bb1..1b3077c7f 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -108,10 +108,8 @@ static sigset_t ttyblock; static struct io_buffer *iobufs; static void flush_output(void); -static int exec_monitor(struct command_details *details, char *argv[], - char *envp[], int backchannel); -static void exec_pty(struct command_details *detail, char *argv[], - char *envp[]); +static int exec_monitor(struct command_details *details, int backchannel); +static void exec_pty(struct command_details *detail); static void sigwinch(int s); static void sync_ttysize(int src, int dst); static void deliver_signal(pid_t pid, int signo); @@ -640,8 +638,7 @@ perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat) * Returns the child pid. */ int -fork_pty(struct command_details *details, char *argv[], char *envp[], - int sv[], int *maxfd) +fork_pty(struct command_details *details, int sv[], int *maxfd) { struct command_status cstat; struct io_buffer *iob; @@ -758,7 +755,7 @@ fork_pty(struct command_details *details, char *argv[], char *envp[], close(io_pipe[STDOUT_FILENO][0]); if (io_pipe[STDERR_FILENO][0]) close(io_pipe[STDERR_FILENO][0]); - exec_monitor(details, argv, envp, sv[1]); + exec_monitor(details, sv[1]); } cstat.type = CMD_ERRNO; cstat.val = errno; @@ -973,8 +970,7 @@ handle_sigchld(int backchannel, struct command_status *cstat) * Returns an error if fork(2) fails, else calls _exit(2). */ static int -exec_monitor(struct command_details *details, char *argv[], char *envp[], - int backchannel) +exec_monitor(struct command_details *details, int backchannel) { struct command_status cstat; struct timeval tv; @@ -1062,7 +1058,7 @@ exec_monitor(struct command_details *details, char *argv[], char *envp[], restore_signals(); /* setup tty and exec command */ - exec_pty(details, argv, envp); + exec_pty(details); cstat.type = CMD_ERRNO; cstat.val = errno; if (write(errpipe[1], &cstat, sizeof(cstat)) == -1) @@ -1258,7 +1254,7 @@ flush_output(void) * Returns only if execve() fails. */ static void -exec_pty(struct command_details *details, char *argv[], char *envp[]) +exec_pty(struct command_details *details) { pid_t self = getpid(); @@ -1291,10 +1287,10 @@ exec_pty(struct command_details *details, char *argv[], char *envp[]) closefrom(details->closefrom); #ifdef HAVE_SELINUX if (ISSET(details->flags, CD_RBAC_ENABLED)) - selinux_execve(details->command, argv, envp); + selinux_execve(details->command, details->argv, details->envp); else #endif - my_execve(details->command, argv, envp); + my_execve(details->command, details->argv, details->envp); } /* diff --git a/src/sudo.c b/src/sudo.c index 34b09c180..9c9c8c198 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -86,6 +86,9 @@ # endif /* __hpux */ # include #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ +#ifdef HAVE_PRIV_SET +# include +#endif #include "sudo.h" #include "sudo_plugin.h" @@ -271,6 +274,8 @@ main(int argc, char *argv[], char *envp[]) } } command_info_to_details(command_info, &command_details); + command_details.argv = argv_out; + command_details.envp = user_env_out; if (ISSET(sudo_mode, MODE_BACKGROUND)) SET(command_details.flags, CD_BACKGROUND); /* Restore coredumpsize resource limit before running. */ @@ -278,7 +283,7 @@ main(int argc, char *argv[], char *envp[]) (void) setrlimit(RLIMIT_CORE, &corelimit); #endif /* RLIMIT_CORE && !SUDO_DEVEL */ if (ISSET(command_details.flags, CD_SUDOEDIT)) { - exitcode = sudo_edit(&command_details, argv_out, user_env_out); + exitcode = sudo_edit(&command_details); } else { if (ISSET(sudo_mode, MODE_SHELL)) { /* Escape meta chars if running a shell with args. */ @@ -286,7 +291,7 @@ main(int argc, char *argv[], char *envp[]) argv_out[2] != NULL && argv_out[3] == NULL) argv_out[2] = escape_cmnd(argv_out[2]); } - exitcode = run_command(&command_details, argv_out, user_env_out); + exitcode = run_command(&command_details); } /* The close method was called by sudo_edit/run_command. */ break; @@ -860,6 +865,14 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd) } } + /* XXX - should do env-based noexec here too */ +#ifdef HAVE_PRIV_SET + if (ISSET(details->flags, CD_NOEXEC)) { + if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == -1) + warning("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT"); + } +#endif /* HAVE_PRIV_SET */ + #ifdef HAVE_SETRESUID if (setresuid(details->uid, details->euid, details->euid) != 0) { warning("unable to change to runas uid (%u, %u)", details->uid, @@ -943,7 +956,7 @@ escape_cmnd(const char *src) * Run the command and wait for it to complete. */ int -run_command(struct command_details *details, char *argv[], char *envp[]) +run_command(struct command_details *details) { struct plugin_container *plugin; struct command_status cstat; @@ -952,7 +965,7 @@ run_command(struct command_details *details, char *argv[], char *envp[]) cstat.type = CMD_INVALID; cstat.val = 0; - sudo_execve(details, argv, envp, &cstat); + sudo_execve(details, &cstat); switch (cstat.type) { case CMD_ERRNO: diff --git a/src/sudo.h b/src/sudo.h index e6190c16c..8c21934b8 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -139,6 +139,8 @@ struct command_details { const char *chroot; const char *selinux_role; const char *selinux_type; + char **argv; + char **envp; }; /* Status passed between parent and child via socketpair */ @@ -165,8 +167,7 @@ extern const char *askpass_path; void zero_bytes(volatile void *, size_t); /* exec.c */ -int sudo_execve(struct command_details *details, char *argv[], char *envp[], - struct command_status *cstat); +int sudo_execve(struct command_details *details, struct command_status *cstat); void save_signals(void); void restore_signals(void); @@ -196,15 +197,14 @@ void get_ttysize(int *rowp, int *colp); /* sudo.c */ int exec_setup(struct command_details *details, const char *ptyname, int ptyfd); -int run_command(struct command_details *details, char *argv[], - char *envp[]); +int run_command(struct command_details *details); void sudo_debug(int level, const char *format, ...) __printflike(2, 3); extern int debug_level; extern const char *list_user, *runas_user, *runas_group; extern struct user_details user_details; /* sudo_edit.c */ -int sudo_edit(struct command_details *details, char *argv[], char *envp[]); +int sudo_edit(struct command_details *details); /* parse_args.c */ void usage(int); diff --git a/src/sudo_edit.c b/src/sudo_edit.c index a08e9435a..dd485d346 100644 --- a/src/sudo_edit.c +++ b/src/sudo_edit.c @@ -82,7 +82,7 @@ switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups) * Wrapper to allow users to edit privileged files with their own uid. */ int -sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) +sudo_edit(struct command_details *command_details) { struct command_details editor_details; ssize_t nread, nwritten; @@ -128,7 +128,7 @@ sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) * The user's editor must be separated from the files to be * edited by a "--" option. */ - for (ap = argv; *ap != NULL; ap++) { + for (ap = command_details->argv; *ap != NULL; ap++) { if (files) nfiles++; else if (strcmp(*ap, "--") == 0) @@ -238,7 +238,7 @@ sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) nargc = editor_argc + nfiles; nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); for (ac = 0; ac < editor_argc; ac++) - nargv[ac] = argv[ac]; + nargv[ac] = command_details->argv[ac]; for (i = 0; i < nfiles && ac < nargc; ) nargv[ac++] = tf[i++].tfile; nargv[ac] = NULL; @@ -255,7 +255,8 @@ sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) editor_details.egid = user_details.gid; editor_details.ngroups = user_details.ngroups; editor_details.groups = user_details.groups; - rval = run_command(&editor_details, nargv, envp); + editor_details.argv = nargv; + rval = run_command(&editor_details); gettimeofday(&tv2, NULL); /* Copy contents of temp files to real ones */ @@ -345,7 +346,7 @@ cleanup: * Must have the ability to change the effective uid to use sudoedit. */ int -sudo_edit(struct command_details *command_details, char *argv[], char *envp[]) +sudo_edit(struct command_details *command_details) { return 1; } diff --git a/src/sudo_exec.h b/src/sudo_exec.h index 7bc3d52ec..d447634b9 100644 --- a/src/sudo_exec.h +++ b/src/sudo_exec.h @@ -32,8 +32,7 @@ int my_execve(const char *path, char *const argv[], char *const envp[]); int pipe_nonblock(int fds[2]); /* exec_pty.c */ -int fork_pty(struct command_details *details, char *argv[], char *envp[], - int sv[], int *maxfd); +int fork_pty(struct command_details *details, int sv[], int *maxfd); int perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat); int suspend_parent(int signo); void fd_set_iobs(fd_set *fdsr, fd_set *fdsw);