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().
This commit is contained in:
Todd C. Miller
2010-06-08 17:59:18 -04:00
parent ecfb70b056
commit edd34a2d7e
5 changed files with 67 additions and 55 deletions

View File

@@ -59,9 +59,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
#endif
/* XXX - move to compat */ /* XXX - move to compat */
#if !defined(NSIG) #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. * Sends errno back on sv[1] if execve() fails.
*/ */
static int fork_cmnd(struct command_details *details, char *argv[], 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; struct command_status cstat;
int pid; int pid;
@@ -127,18 +124,12 @@ static int fork_cmnd(struct command_details *details, char *argv[],
/* child */ /* child */
close(sv[0]); close(sv[0]);
fcntl(sv[1], F_SETFD, FD_CLOEXEC); fcntl(sv[1], F_SETFD, FD_CLOEXEC);
#ifdef HAVE_SELINUX if (exec_setup(details, NULL, -1) == TRUE) {
if (rbac_enabled) {
selinux_setup(details->selinux_role, details->selinux_type,
user_details.tty, -1);
}
#endif
if (exec_setup(details) == TRUE) {
/* headed for execve() */ /* headed for execve() */
if (details->closefrom >= 0) if (details->closefrom >= 0)
closefrom(details->closefrom); closefrom(details->closefrom);
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (rbac_enabled) if (details->selinux_enabled)
selinux_execve(details->command, argv, envp); selinux_execve(details->command, argv, envp);
else else
#endif #endif
@@ -164,7 +155,6 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[],
sigaction_t sa; sigaction_t sa;
fd_set *fdsr, *fdsw; fd_set *fdsr, *fdsw;
int maxfd, n, nready, status, sv[2]; int maxfd, n, nready, status, sv[2];
int rbac_enabled = 0;
int log_io = 0; int log_io = 0;
pid_t child; pid_t child;
@@ -176,10 +166,6 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[],
pty_setup(details->euid); 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. * We communicate with the child over a bi-directional pair of sockets.
* Parent sends signal info to child and child sends back wait status. * 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. * to and from pty. Adjusts maxfd as needed.
*/ */
if (log_io) if (log_io)
child = fork_pty(details, argv, envp, sv, rbac_enabled, &maxfd); child = fork_pty(details, argv, envp, sv, &maxfd);
else else
child = fork_cmnd(details, argv, envp, sv, rbac_enabled); child = fork_cmnd(details, argv, envp, sv);
close(sv[1]); close(sv[1]);
/* Set command timeout if specified. */ /* Set command timeout if specified. */
@@ -343,7 +329,7 @@ sudo_execve(struct command_details *details, char *argv[], char *envp[],
} }
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (rbac_enabled) { if (details->selinux_enabled) {
/* This is probably not needed in log_io mode. */ /* This is probably not needed in log_io mode. */
if (selinux_restore_tty() != 0) if (selinux_restore_tty() != 0)
warningx("unable to restore tty label"); warningx("unable to restore tty label");

View File

@@ -118,9 +118,9 @@ static struct io_buffer *iobufs;
static void flush_output(void); static void flush_output(void);
static int exec_monitor(struct command_details *details, char *argv[], 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[], static void exec_pty(struct command_details *detail, char *argv[],
char *envp[], int); char *envp[]);
static void sigwinch(int s); static void sigwinch(int s);
static void sync_ttysize(int src, int dst); static void sync_ttysize(int src, int dst);
static void deliver_signal(pid_t pid, int signo); 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 int
fork_pty(struct command_details *details, char *argv[], char *envp[], 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 command_status cstat;
struct io_buffer *iob; struct io_buffer *iob;
@@ -581,13 +581,7 @@ fork_pty(struct command_details *details, char *argv[], char *envp[],
/* child */ /* child */
close(sv[0]); close(sv[0]);
fcntl(sv[1], F_SETFD, FD_CLOEXEC); fcntl(sv[1], F_SETFD, FD_CLOEXEC);
#ifdef HAVE_SELINUX if (exec_setup(details, slavename, io_fds[SFD_SLAVE]) == TRUE) {
if (rbac_enabled) {
selinux_setup(details->selinux_role, details->selinux_type,
slavename, io_fds[SFD_SLAVE]);
}
#endif
if (exec_setup(details) == TRUE) {
/* Close the other end of the stdin/stdout/stderr pipes and exec. */ /* Close the other end of the stdin/stdout/stderr pipes and exec. */
if (io_pipe[STDIN_FILENO][1]) if (io_pipe[STDIN_FILENO][1])
close(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]); close(io_pipe[STDOUT_FILENO][0]);
if (io_pipe[STDERR_FILENO][0]) if (io_pipe[STDERR_FILENO][0])
close(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.type = CMD_ERRNO;
cstat.val = errno; cstat.val = errno;
@@ -814,7 +808,7 @@ handle_sigchld(int backchannel, struct command_status *cstat)
*/ */
int int
exec_monitor(struct command_details *details, char *argv[], char *envp[], exec_monitor(struct command_details *details, char *argv[], char *envp[],
int backchannel, int rbac) int backchannel)
{ {
struct command_status cstat; struct command_status cstat;
struct timeval tv; struct timeval tv;
@@ -904,7 +898,7 @@ exec_monitor(struct command_details *details, char *argv[], char *envp[],
fcntl(errpipe[1], F_SETFD, FD_CLOEXEC); fcntl(errpipe[1], F_SETFD, FD_CLOEXEC);
/* setup tty and exec command */ /* setup tty and exec command */
exec_pty(details, argv, envp, rbac); exec_pty(details, argv, envp);
cstat.type = CMD_ERRNO; cstat.type = CMD_ERRNO;
cstat.val = errno; cstat.val = errno;
write(errpipe[1], &cstat, sizeof(cstat)); write(errpipe[1], &cstat, sizeof(cstat));
@@ -1088,8 +1082,7 @@ flush_output(void)
* Returns only if execve() fails. * Returns only if execve() fails.
*/ */
static void static void
exec_pty(struct command_details *details, char *argv[], char *envp[], exec_pty(struct command_details *details, char *argv[], char *envp[])
int rbac_enabled)
{ {
sigaction_t sa; sigaction_t sa;
pid_t self = getpid(); pid_t self = getpid();
@@ -1137,7 +1130,7 @@ exec_pty(struct command_details *details, char *argv[], char *envp[],
if (details->closefrom >= 0) if (details->closefrom >= 0)
closefrom(details->closefrom); closefrom(details->closefrom);
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (rbac_enabled) if (details->selinux_enabled)
selinux_execve(details->command, argv, envp); selinux_execve(details->command, argv, envp);
else else
#endif #endif

View File

@@ -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). */ /* We must have a role, the type is optional (we can use the default). */
if (!role) { if (!role) {
warningx("you must specify a role."); warningx("you must specify a role for type %s", type);
errno = EINVAL;
return NULL; return NULL;
} }
if (!type) { if (!type) {
if (get_default_type(role, &typebuf)) { 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; return NULL;
} }
type = typebuf; 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. * type we will be running the command as.
*/ */
if (context_role_set(context, role)) { if (context_role_set(context, role)) {
warningx("failed to set new role %s", role); warning("failed to set new role %s", role);
goto bad; goto bad;
} }
if (context_type_set(context, type)) { if (context_type_set(context, type)) {
warningx("failed to set new type %s", type); warning("failed to set new type %s", type);
goto bad; 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)); new_context = estrdup(context_str(context));
if (security_check_context(new_context) < 0) { if (security_check_context(new_context) < 0) {
warningx("%s is not a valid context", new_context); warningx("%s is not a valid context", new_context);
errno = EINVAL;
goto bad; goto bad;
} }
@@ -263,28 +266,37 @@ bad:
* Must run as root, before the uid change. * Must run as root, before the uid change.
* If ptyfd is not -1, it indicates we are running * If ptyfd is not -1, it indicates we are running
* in a pty and do not need to reset std{in,out,err}. * 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, selinux_setup(const char *role, const char *type, const char *ttyn,
int ptyfd) int ptyfd)
{ {
int rval = -1;
/* Store the caller's SID in old_context. */ /* Store the caller's SID in old_context. */
if (getprevcon(&se_state.old_context)) if (getprevcon(&se_state.old_context)) {
error(EXIT_FAILURE, "failed to get old_context"); warning("failed to get old_context");
goto done;
}
se_state.enforcing = security_getenforce(); se_state.enforcing = security_getenforce();
if (se_state.enforcing < 0) if (se_state.enforcing < 0) {
error(EXIT_FAILURE, "unable to determine enforcing mode."); warning("unable to determine enforcing mode.");
goto done;
}
#ifdef DEBUG #ifdef DEBUG
warningx("your old context was %s", se_state.old_context); warningx("your old context was %s", se_state.old_context);
#endif #endif
se_state.new_context = get_exec_context(se_state.old_context, role, type); se_state.new_context = get_exec_context(se_state.old_context, role, type);
if (!se_state.new_context) if (!se_state.new_context)
error(EXIT_FAILURE, "unable to get exec context"); goto done;
if (relabel_tty(ttyn, ptyfd) < 0) if (relabel_tty(ttyn, ptyfd) < 0) {
error(EXIT_FAILURE, "unable to setup tty context for %s", se_state.new_context); warning("unable to setup tty context for %s", se_state.new_context);
goto done;
}
#ifdef DEBUG #ifdef DEBUG
if (se_state.ttyfd != -1) { if (se_state.ttyfd != -1) {
@@ -293,6 +305,10 @@ selinux_setup(const char *role, const char *type, const char *ttyn,
} }
#endif #endif
rval = 0;
done:
return rval;
} }
void void

View File

@@ -69,6 +69,9 @@
#ifdef HAVE_LOGIN_CAP_H #ifdef HAVE_LOGIN_CAP_H
# include <login_cap.h> # include <login_cap.h>
#endif #endif
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
#endif
#include "sudo.h" #include "sudo.h"
#include "sudo_plugin.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)) if (!ISSET(details->flags, CD_SET_EUID))
details->euid = details->uid; 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. * Returns TRUE on success and FALSE on failure.
*/ */
int int
exec_setup(struct command_details *details) exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
{ {
int rval = FALSE; int rval = FALSE;
struct passwd *pw; struct passwd *pw;
@@ -644,6 +652,14 @@ exec_setup(struct command_details *details)
goto done; 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) { if (pw != NULL) {
#ifdef HAVE_GETUSERATTR #ifdef HAVE_GETUSERATTR
aix_setlimits(pw->pw_name); aix_setlimits(pw->pw_name);

View File

@@ -123,11 +123,12 @@ struct command_details {
gid_t gid; gid_t gid;
gid_t egid; gid_t egid;
mode_t umask; mode_t umask;
int flags;
int priority; int priority;
int timeout; int timeout;
int ngroups; int ngroups;
int closefrom; int closefrom;
short flags;
short selinux_enabled;
GETGROUPS_T *groups; GETGROUPS_T *groups;
const char *command; const char *command;
const char *cwd; const char *cwd;
@@ -164,7 +165,7 @@ int my_execve(const char *path, char *const argv[], char *const envp[]);
/* exec_pty.c */ /* exec_pty.c */
int fork_pty(struct command_details *details, char *argv[], char *envp[], 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 perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat);
int suspend_parent(int signo); int suspend_parent(int signo);
void fd_set_iobs(fd_set *fdsr, fd_set *fdsw); 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); void get_ttysize(int *linep, int *colp);
/* sudo.c */ /* 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[], int run_command(struct command_details *details, char *argv[],
char *envp[]); char *envp[]);
void sudo_debug(int level, const char *format, ...) __printflike(2, 3); void sudo_debug(int level, const char *format, ...) __printflike(2, 3);
@@ -213,10 +214,10 @@ void usage(int) __attribute__((__noreturn__));
int gettime(struct timeval *); int gettime(struct timeval *);
/* selinux.c */ /* 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_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 #ifndef errno
extern int errno; extern int errno;