From edd34a2d7e0d99418cba88353521ea2a508f54a7 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 8 Jun 2010 17:59:18 -0400 Subject: [PATCH] Add selinux_enabled flag into struct command_details and set it in command_info_to_details(). Return an error from selinux_setup() instead of exiting. Call selinux_setup() from exec_setup(). --- src/exec.c | 26 ++++++-------------------- src/exec_pty.c | 25 +++++++++---------------- src/selinux.c | 40 ++++++++++++++++++++++++++++------------ src/sudo.c | 18 +++++++++++++++++- src/sudo.h | 13 +++++++------ 5 files changed, 67 insertions(+), 55 deletions(-) diff --git a/src/exec.c b/src/exec.c index c704abe7a..2e8cc932d 100644 --- a/src/exec.c +++ b/src/exec.c @@ -59,9 +59,6 @@ #include #include #include -#ifdef HAVE_SELINUX -# include -#endif /* XXX - move to compat */ #if !defined(NSIG) @@ -113,7 +110,7 @@ my_execve(const char *path, char *const argv[], char *const envp[]) * Sends errno back on sv[1] if execve() fails. */ static int fork_cmnd(struct command_details *details, char *argv[], - char *envp[], int sv[2], int rbac_enabled) + char *envp[], int sv[2]) { struct command_status cstat; int pid; @@ -127,18 +124,12 @@ static int fork_cmnd(struct command_details *details, char *argv[], /* child */ close(sv[0]); fcntl(sv[1], F_SETFD, FD_CLOEXEC); -#ifdef HAVE_SELINUX - if (rbac_enabled) { - selinux_setup(details->selinux_role, details->selinux_type, - user_details.tty, -1); - } -#endif - if (exec_setup(details) == TRUE) { + if (exec_setup(details, NULL, -1) == TRUE) { /* headed for execve() */ if (details->closefrom >= 0) closefrom(details->closefrom); #ifdef HAVE_SELINUX - if (rbac_enabled) + if (details->selinux_enabled) selinux_execve(details->command, argv, envp); else #endif @@ -164,7 +155,6 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[], sigaction_t sa; fd_set *fdsr, *fdsw; int maxfd, n, nready, status, sv[2]; - int rbac_enabled = 0; int log_io = 0; pid_t child; @@ -176,10 +166,6 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[], pty_setup(details->euid); } -#ifdef HAVE_SELINUX - rbac_enabled = is_selinux_enabled() > 0 && details->selinux_role != NULL; -#endif - /* * We communicate with the child over a bi-directional pair of sockets. * Parent sends signal info to child and child sends back wait status. @@ -209,9 +195,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, rbac_enabled, &maxfd); + child = fork_pty(details, argv, envp, sv, &maxfd); else - child = fork_cmnd(details, argv, envp, sv, rbac_enabled); + child = fork_cmnd(details, argv, envp, sv); close(sv[1]); /* Set command timeout if specified. */ @@ -343,7 +329,7 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[], } #ifdef HAVE_SELINUX - if (rbac_enabled) { + if (details->selinux_enabled) { /* This is probably not needed in log_io mode. */ if (selinux_restore_tty() != 0) warningx("unable to restore tty label"); diff --git a/src/exec_pty.c b/src/exec_pty.c index 8e3f35644..242e842c0 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -118,9 +118,9 @@ static struct io_buffer *iobufs; static void flush_output(void); static int exec_monitor(struct command_details *details, char *argv[], - char *envp[], int, int); + char *envp[], int backchannel); static void exec_pty(struct command_details *detail, char *argv[], - char *envp[], int); + char *envp[]); static void sigwinch(int s); static void sync_ttysize(int src, int dst); static void deliver_signal(pid_t pid, int signo); @@ -470,7 +470,7 @@ perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat) */ int fork_pty(struct command_details *details, char *argv[], char *envp[], - int sv[], int rbac_enabled, int *maxfd) + int sv[], int *maxfd) { struct command_status cstat; struct io_buffer *iob; @@ -581,13 +581,7 @@ fork_pty(struct command_details *details, char *argv[], char *envp[], /* child */ close(sv[0]); fcntl(sv[1], F_SETFD, FD_CLOEXEC); -#ifdef HAVE_SELINUX - if (rbac_enabled) { - selinux_setup(details->selinux_role, details->selinux_type, - slavename, io_fds[SFD_SLAVE]); - } -#endif - if (exec_setup(details) == TRUE) { + if (exec_setup(details, slavename, io_fds[SFD_SLAVE]) == TRUE) { /* Close the other end of the stdin/stdout/stderr pipes and exec. */ if (io_pipe[STDIN_FILENO][1]) close(io_pipe[STDIN_FILENO][1]); @@ -595,7 +589,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], rbac_enabled); + exec_monitor(details, argv, envp, sv[1]); } cstat.type = CMD_ERRNO; cstat.val = errno; @@ -814,7 +808,7 @@ handle_sigchld(int backchannel, struct command_status *cstat) */ int exec_monitor(struct command_details *details, char *argv[], char *envp[], - int backchannel, int rbac) + int backchannel) { struct command_status cstat; struct timeval tv; @@ -904,7 +898,7 @@ exec_monitor(struct command_details *details, char *argv[], char *envp[], fcntl(errpipe[1], F_SETFD, FD_CLOEXEC); /* setup tty and exec command */ - exec_pty(details, argv, envp, rbac); + exec_pty(details, argv, envp); cstat.type = CMD_ERRNO; cstat.val = errno; write(errpipe[1], &cstat, sizeof(cstat)); @@ -1088,8 +1082,7 @@ flush_output(void) * Returns only if execve() fails. */ static void -exec_pty(struct command_details *details, char *argv[], char *envp[], - int rbac_enabled) +exec_pty(struct command_details *details, char *argv[], char *envp[]) { sigaction_t sa; pid_t self = getpid(); @@ -1137,7 +1130,7 @@ exec_pty(struct command_details *details, char *argv[], char *envp[], if (details->closefrom >= 0) closefrom(details->closefrom); #ifdef HAVE_SELINUX - if (rbac_enabled) + if (details->selinux_enabled) selinux_execve(details->command, argv, envp); else #endif diff --git a/src/selinux.c b/src/selinux.c index 54b839fea..0c70710ea 100644 --- a/src/selinux.c +++ b/src/selinux.c @@ -205,12 +205,14 @@ get_exec_context(security_context_t old_context, const char *role, const char *t /* We must have a role, the type is optional (we can use the default). */ if (!role) { - warningx("you must specify a role."); + warningx("you must specify a role for type %s", type); + errno = EINVAL; return NULL; } if (!type) { if (get_default_type(role, &typebuf)) { - warningx("unable to get default type"); + warningx("unable to get default type for role %s", role); + errno = EINVAL; return NULL; } type = typebuf; @@ -227,11 +229,11 @@ get_exec_context(security_context_t old_context, const char *role, const char *t * type we will be running the command as. */ if (context_role_set(context, role)) { - warningx("failed to set new role %s", role); + warning("failed to set new role %s", role); goto bad; } if (context_type_set(context, type)) { - warningx("failed to set new type %s", type); + warning("failed to set new type %s", type); goto bad; } @@ -241,6 +243,7 @@ get_exec_context(security_context_t old_context, const char *role, const char *t new_context = estrdup(context_str(context)); if (security_check_context(new_context) < 0) { warningx("%s is not a valid context", new_context); + errno = EINVAL; goto bad; } @@ -263,28 +266,37 @@ bad: * Must run as root, before the uid change. * If ptyfd is not -1, it indicates we are running * in a pty and do not need to reset std{in,out,err}. + * Returns 0 on success and -1 on failure. */ -void +int selinux_setup(const char *role, const char *type, const char *ttyn, int ptyfd) { + int rval = -1; + /* Store the caller's SID in old_context. */ - if (getprevcon(&se_state.old_context)) - error(EXIT_FAILURE, "failed to get old_context"); + if (getprevcon(&se_state.old_context)) { + warning("failed to get old_context"); + goto done; + } se_state.enforcing = security_getenforce(); - if (se_state.enforcing < 0) - error(EXIT_FAILURE, "unable to determine enforcing mode."); + if (se_state.enforcing < 0) { + warning("unable to determine enforcing mode."); + goto done; + } #ifdef DEBUG warningx("your old context was %s", se_state.old_context); #endif se_state.new_context = get_exec_context(se_state.old_context, role, type); if (!se_state.new_context) - error(EXIT_FAILURE, "unable to get exec context"); + goto done; - if (relabel_tty(ttyn, ptyfd) < 0) - error(EXIT_FAILURE, "unable to setup tty context for %s", se_state.new_context); + if (relabel_tty(ttyn, ptyfd) < 0) { + warning("unable to setup tty context for %s", se_state.new_context); + goto done; + } #ifdef DEBUG if (se_state.ttyfd != -1) { @@ -293,6 +305,10 @@ selinux_setup(const char *role, const char *type, const char *ttyn, } #endif + rval = 0; + +done: + return rval; } void diff --git a/src/sudo.c b/src/sudo.c index d500d84eb..fae862271 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -69,6 +69,9 @@ #ifdef HAVE_LOGIN_CAP_H # include #endif +#ifdef HAVE_SELINUX +# include +#endif #include "sudo.h" #include "sudo_plugin.h" @@ -586,6 +589,11 @@ command_info_to_details(char * const info[], struct command_details *details) if (!ISSET(details->flags, CD_SET_EUID)) details->euid = details->uid; + +#ifdef HAVE_SELINUX + if (details->selinux_role != NULL && is_selinux_enabled() > 0) + details->selinux_enabled = TRUE; +#endif } /* @@ -630,7 +638,7 @@ disable_coredumps(void) * Returns TRUE on success and FALSE on failure. */ int -exec_setup(struct command_details *details) +exec_setup(struct command_details *details, const char *ptyname, int ptyfd) { int rval = FALSE; struct passwd *pw; @@ -644,6 +652,14 @@ exec_setup(struct command_details *details) goto done; } +#ifdef HAVE_SELINUX + if (details->selinux_enabled) { + if (selinux_setup(details->selinux_role, details->selinux_type, + ptyname ? ptyname : user_details.tty, ptyfd) == -1) + goto done; + } +#endif + if (pw != NULL) { #ifdef HAVE_GETUSERATTR aix_setlimits(pw->pw_name); diff --git a/src/sudo.h b/src/sudo.h index f0112a20a..dbda4f601 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -123,11 +123,12 @@ struct command_details { gid_t gid; gid_t egid; mode_t umask; - int flags; int priority; int timeout; int ngroups; int closefrom; + short flags; + short selinux_enabled; GETGROUPS_T *groups; const char *command; const char *cwd; @@ -164,7 +165,7 @@ int my_execve(const char *path, char *const argv[], char *const envp[]); /* exec_pty.c */ int fork_pty(struct command_details *details, char *argv[], char *envp[], - int sv[], int rbac_enabled, int *maxfd); + 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); @@ -196,7 +197,7 @@ int get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid); void get_ttysize(int *linep, int *colp); /* sudo.c */ -int exec_setup(struct command_details *details); +int exec_setup(struct command_details *details, const char *ptyname, int ptyfd); int run_command(struct command_details *details, char *argv[], char *envp[]); void sudo_debug(int level, const char *format, ...) __printflike(2, 3); @@ -213,10 +214,10 @@ void usage(int) __attribute__((__noreturn__)); int gettime(struct timeval *); /* selinux.c */ -void selinux_execve(const char *path, char *argv[], char *envp[]); -void selinux_setup(const char *role, const char *type, const char *ttyn, - int ttyfd); 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 *argv[], char *envp[]); #ifndef errno extern int errno; -- 2.40.0