Separate out the code to compute the context from selinux_setup().
This makes it possible to determine whether we really need to execute the command via the sesh helper. What was left of selinux_setup() is now selinux_relabel_tty() and selinux_audit_role_change().
This commit is contained in:
@@ -605,9 +605,9 @@ exec_monitor(struct command_details *details, sigset_t *oset,
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
||||
if (selinux_setup(details->selinux_role, details->selinux_type,
|
||||
details->tty, io_fds[SFD_FOLLOWER], true) == -1)
|
||||
if (selinux_relabel_tty(details->tty, io_fds[SFD_FOLLOWER]) == -1)
|
||||
goto bad;
|
||||
selinux_audit_role_change();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -392,12 +392,12 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
||||
if (selinux_setup(details->selinux_role, details->selinux_type,
|
||||
details->tty, -1, true) == -1) {
|
||||
if (selinux_relabel_tty(details->tty, -1) == -1) {
|
||||
cstat->type = CMD_ERRNO;
|
||||
cstat->val = errno;
|
||||
debug_return;
|
||||
}
|
||||
selinux_audit_role_change();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -67,14 +67,13 @@ static struct selinux_state {
|
||||
int enforcing;
|
||||
} se_state;
|
||||
|
||||
#ifdef HAVE_LINUX_AUDIT
|
||||
static int
|
||||
audit_role_change(const char * old_context,
|
||||
const char * new_context, const char *ttyn, int result)
|
||||
int
|
||||
selinux_audit_role_change(void)
|
||||
{
|
||||
#ifdef HAVE_LINUX_AUDIT
|
||||
int au_fd, rc = -1;
|
||||
char *message;
|
||||
debug_decl(audit_role_change, SUDO_DEBUG_SELINUX);
|
||||
debug_decl(selinux_audit_role_change, SUDO_DEBUG_SELINUX);
|
||||
|
||||
au_fd = audit_open();
|
||||
if (au_fd == -1) {
|
||||
@@ -85,11 +84,11 @@ audit_role_change(const char * old_context,
|
||||
} else {
|
||||
/* audit role change using the same format as newrole(1) */
|
||||
rc = asprintf(&message, "newrole: old-context=%s new-context=%s",
|
||||
old_context, new_context);
|
||||
se_state.old_context, se_state.new_context ? se_state.new_context : ? "?");
|
||||
if (rc == -1)
|
||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE,
|
||||
message, NULL, NULL, ttyn, result);
|
||||
message, NULL, NULL, se_state.ttyn, se_state.new_context ? 1 : 0);
|
||||
if (rc <= 0)
|
||||
sudo_warn("%s", U_("unable to send audit message"));
|
||||
free(message);
|
||||
@@ -97,8 +96,10 @@ audit_role_change(const char * old_context,
|
||||
}
|
||||
|
||||
debug_return_int(rc);
|
||||
#else
|
||||
return 0;
|
||||
#endif /* HAVE_LINUX_AUDIT */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function attempts to revert the relabeling done to the tty.
|
||||
@@ -163,8 +164,8 @@ skip_relabel:
|
||||
* This function will not fail if it can not relabel the tty when selinux is
|
||||
* in permissive mode.
|
||||
*/
|
||||
static int
|
||||
relabel_tty(const char *ttyn, int ptyfd)
|
||||
int
|
||||
selinux_relabel_tty(const char *ttyn, int ptyfd)
|
||||
{
|
||||
char * tty_con = NULL;
|
||||
char * new_tty_con = NULL;
|
||||
@@ -305,38 +306,39 @@ bad:
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new security context based on the old context and the
|
||||
* Determine the new security context based on the old context and the
|
||||
* specified role and type.
|
||||
* Returns 0 on success, and -1 on failure.
|
||||
*/
|
||||
static char *
|
||||
get_exec_context(char *old_context, const char *role, const char *type)
|
||||
static int
|
||||
get_exec_context(const char *role, const char *type)
|
||||
{
|
||||
char *rolebuf = NULL, *typebuf = NULL;
|
||||
char *new_context = NULL;
|
||||
context_t context = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(get_exec_context, SUDO_DEBUG_SELINUX);
|
||||
|
||||
/*
|
||||
* Expand old_context into a context_t so that we can extract and modify
|
||||
* its components easily.
|
||||
*/
|
||||
if ((context = context_new(old_context)) == NULL) {
|
||||
if ((context = context_new(se_state.old_context)) == NULL) {
|
||||
sudo_warn("%s", U_("failed to get new context"));
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (role == NULL) {
|
||||
/* TODO: if role is unconfined_r and type is NULL, disable SELinux */
|
||||
rolebuf = strdup(context_role_get(context));
|
||||
if (rolebuf == NULL)
|
||||
goto bad;
|
||||
goto done;
|
||||
role = rolebuf;
|
||||
}
|
||||
if (type == NULL) {
|
||||
if (get_default_type(role, &typebuf)) {
|
||||
sudo_warnx(U_("unable to get default type for role %s"), role);
|
||||
errno = EINVAL;
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
type = typebuf;
|
||||
}
|
||||
@@ -347,11 +349,11 @@ get_exec_context(char *old_context, const char *role, const char *type)
|
||||
*/
|
||||
if (context_role_set(context, role)) {
|
||||
sudo_warn(U_("failed to set new role %s"), role);
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
if (context_type_set(context, type)) {
|
||||
sudo_warn(U_("failed to set new type %s"), type);
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -359,39 +361,35 @@ get_exec_context(char *old_context, const char *role, const char *type)
|
||||
*/
|
||||
if ((new_context = strdup(context_str(context))) == NULL) {
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
if (security_check_context(new_context) == -1) {
|
||||
sudo_warnx(U_("%s is not a valid context"), new_context);
|
||||
errno = EINVAL;
|
||||
goto bad;
|
||||
goto done;
|
||||
}
|
||||
|
||||
context_free(context);
|
||||
debug_return_str(new_context);
|
||||
se_state.new_context = new_context;
|
||||
new_context = NULL;
|
||||
ret = 0;
|
||||
|
||||
bad:
|
||||
done:
|
||||
free(rolebuf);
|
||||
free(typebuf);
|
||||
context_free(context);
|
||||
freecon(new_context);
|
||||
debug_return_str(NULL);
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the exec and tty contexts in preparation for fork/exec.
|
||||
* Must run as root, before forking the child process.
|
||||
* Sets the tty context but not the exec context (which happens later).
|
||||
* 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.
|
||||
* Determine the exec and tty contexts the command will run in.
|
||||
* Returns 0 on success, 1 if SELinux is not needed, and -1 on failure.
|
||||
*/
|
||||
int
|
||||
selinux_setup(const char *role, const char *type, const char *ttyn,
|
||||
int ptyfd, bool label_tty)
|
||||
selinux_getexeccon(const char *role, const char *type)
|
||||
{
|
||||
int ret = -1;
|
||||
debug_decl(selinux_setup, SUDO_DEBUG_SELINUX);
|
||||
debug_decl(selinux_getexeccon, SUDO_DEBUG_SELINUX);
|
||||
|
||||
/* Store the caller's SID in old_context. */
|
||||
if (getprevcon(&se_state.old_context)) {
|
||||
@@ -407,28 +405,15 @@ selinux_setup(const char *role, const char *type, const char *ttyn,
|
||||
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: old context %s", __func__,
|
||||
se_state.old_context);
|
||||
se_state.new_context = get_exec_context(se_state.old_context, role, type);
|
||||
if (se_state.new_context == NULL) {
|
||||
#ifdef HAVE_LINUX_AUDIT
|
||||
audit_role_change(se_state.old_context, "?", se_state.ttyn, 0);
|
||||
#endif
|
||||
ret = get_exec_context(role, type);
|
||||
if (ret == -1) {
|
||||
/* Audit role change failure (success is logged later). */
|
||||
selinux_audit_role_change();
|
||||
goto done;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: new context %s", __func__,
|
||||
se_state.new_context);
|
||||
|
||||
if (label_tty && relabel_tty(ttyn, ptyfd) == -1) {
|
||||
sudo_warn(U_("unable to set tty context to %s"), se_state.new_context);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_AUDIT
|
||||
audit_role_change(se_state.old_context, se_state.new_context,
|
||||
se_state.ttyn, 1);
|
||||
#endif
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
13
src/sudo.c
13
src/sudo.c
@@ -887,8 +887,19 @@ command_info_to_details(char * const info[], struct command_details *details)
|
||||
/* Newer sudoers plugin sets selinux_rbac, older only sets role/type. */
|
||||
if (selinux_rbac == -1)
|
||||
selinux_rbac = details->selinux_role || details->selinux_type;
|
||||
if (selinux_rbac && is_selinux_enabled() > 0)
|
||||
if (selinux_rbac && is_selinux_enabled() > 0) {
|
||||
i = selinux_getexeccon(details->selinux_role, details->selinux_type);
|
||||
switch (i) {
|
||||
case 0:
|
||||
SET(details->flags, CD_RBAC_ENABLED);
|
||||
break;
|
||||
case 1:
|
||||
/* No role change needed. */
|
||||
break;
|
||||
default:
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
debug_return;
|
||||
}
|
||||
|
@@ -246,9 +246,10 @@ void usage(void) __attribute__((__noreturn__));
|
||||
int os_init_openbsd(int argc, char *argv[], char *envp[]);
|
||||
|
||||
/* selinux.c */
|
||||
int selinux_audit_role_change(void);
|
||||
int selinux_getexeccon(const char *role, const char *type);
|
||||
int selinux_relabel_tty(const char *ttyn, int ttyfd);
|
||||
int selinux_restore_tty(void);
|
||||
int selinux_setup(const char *role, const char *type, const char *ttyn,
|
||||
int ttyfd, bool label_tty);
|
||||
int selinux_setcon(void);
|
||||
void selinux_execve(int fd, const char *path, char *const argv[],
|
||||
char *envp[], bool noexec);
|
||||
|
@@ -671,15 +671,6 @@ sudo_edit(struct command_details *command_details)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
/* Compute new SELinux security context. */
|
||||
if (ISSET(command_details->flags, CD_RBAC_ENABLED)) {
|
||||
if (selinux_setup(command_details->selinux_role,
|
||||
command_details->selinux_type, NULL, -1, false) != 0)
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copy editor files to temporaries. */
|
||||
tf = calloc(nfiles, sizeof(*tf));
|
||||
if (tf == NULL) {
|
||||
@@ -722,6 +713,10 @@ sudo_edit(struct command_details *command_details)
|
||||
sudo_warn("%s", U_("unable to read the clock"));
|
||||
goto cleanup;
|
||||
}
|
||||
#ifdef HAVE_SELINUX
|
||||
if (ISSET(command_details->flags, CD_RBAC_ENABLED))
|
||||
selinux_audit_role_change();
|
||||
#endif
|
||||
memcpy(&saved_command_details, command_details, sizeof(struct command_details));
|
||||
command_details->cred = user_details.cred;
|
||||
command_details->cred.euid = user_details.cred.uid;
|
||||
|
Reference in New Issue
Block a user