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