|
|
230a1d |
diff -up ./src/exec_monitor.c.symbolic-link-attack-3 ./src/exec_monitor.c
|
|
|
230a1d |
--- ./src/exec_monitor.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
|
|
230a1d |
+++ ./src/exec_monitor.c 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -613,7 +613,7 @@ exec_monitor(struct command_details *det
|
|
|
230a1d |
#ifdef HAVE_SELINUX
|
|
|
230a1d |
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
|
|
230a1d |
if (selinux_setup(details->selinux_role, details->selinux_type,
|
|
|
230a1d |
- details->tty, io_fds[SFD_SLAVE]) == -1)
|
|
|
230a1d |
+ details->tty, io_fds[SFD_SLAVE], true) == -1)
|
|
|
230a1d |
goto bad;
|
|
|
230a1d |
}
|
|
|
230a1d |
#endif
|
|
|
230a1d |
diff -up ./src/exec_nopty.c.symbolic-link-attack-3 ./src/exec_nopty.c
|
|
|
230a1d |
--- ./src/exec_nopty.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
|
|
230a1d |
+++ ./src/exec_nopty.c 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -381,7 +381,7 @@ exec_nopty(struct command_details *detai
|
|
|
230a1d |
#ifdef HAVE_SELINUX
|
|
|
230a1d |
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
|
|
230a1d |
if (selinux_setup(details->selinux_role, details->selinux_type,
|
|
|
230a1d |
- details->tty, -1) == -1) {
|
|
|
230a1d |
+ details->tty, -1, true) == -1) {
|
|
|
230a1d |
cstat->type = CMD_ERRNO;
|
|
|
230a1d |
cstat->val = errno;
|
|
|
230a1d |
debug_return;
|
|
|
230a1d |
diff -up ./src/selinux.c.symbolic-link-attack-3 ./src/selinux.c
|
|
|
230a1d |
--- ./src/selinux.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
|
|
230a1d |
+++ ./src/selinux.c 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -363,7 +363,7 @@ bad:
|
|
|
230a1d |
*/
|
|
|
230a1d |
int
|
|
|
230a1d |
selinux_setup(const char *role, const char *type, const char *ttyn,
|
|
|
230a1d |
- int ptyfd)
|
|
|
230a1d |
+ int ptyfd, bool label_tty)
|
|
|
230a1d |
{
|
|
|
230a1d |
int ret = -1;
|
|
|
230a1d |
debug_decl(selinux_setup, SUDO_DEBUG_SELINUX)
|
|
|
230a1d |
@@ -392,7 +392,7 @@ selinux_setup(const char *role, const ch
|
|
|
230a1d |
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: new context %s", __func__,
|
|
|
230a1d |
se_state.new_context);
|
|
|
230a1d |
|
|
|
230a1d |
- if (relabel_tty(ttyn, ptyfd) == -1) {
|
|
|
230a1d |
+ if (label_tty && relabel_tty(ttyn, ptyfd) == -1) {
|
|
|
230a1d |
sudo_warn(U_("unable to set tty context to %s"), se_state.new_context);
|
|
|
230a1d |
goto done;
|
|
|
230a1d |
}
|
|
|
230a1d |
@@ -408,6 +408,28 @@ done:
|
|
|
230a1d |
debug_return_int(ret);
|
|
|
230a1d |
}
|
|
|
230a1d |
|
|
|
230a1d |
+int
|
|
|
230a1d |
+selinux_setcon(void)
|
|
|
230a1d |
+{
|
|
|
230a1d |
+ debug_decl(selinux_setcon, SUDO_DEBUG_SELINUX);
|
|
|
230a1d |
+
|
|
|
230a1d |
+ if (setexeccon(se_state.new_context)) {
|
|
|
230a1d |
+ sudo_warn(U_("unable to set exec context to %s"), se_state.new_context);
|
|
|
230a1d |
+ if (se_state.enforcing)
|
|
|
230a1d |
+ debug_return_int(-1);
|
|
|
230a1d |
+ }
|
|
|
230a1d |
+
|
|
|
230a1d |
+#ifdef HAVE_SETKEYCREATECON
|
|
|
230a1d |
+ if (setkeycreatecon(se_state.new_context)) {
|
|
|
230a1d |
+ sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context);
|
|
|
230a1d |
+ if (se_state.enforcing)
|
|
|
230a1d |
+ debug_return_int(-1);
|
|
|
230a1d |
+ }
|
|
|
230a1d |
+#endif /* HAVE_SETKEYCREATECON */
|
|
|
230a1d |
+
|
|
|
230a1d |
+ debug_return_int(0);
|
|
|
230a1d |
+}
|
|
|
230a1d |
+
|
|
|
230a1d |
void
|
|
|
230a1d |
selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
|
|
|
230a1d |
bool noexec)
|
|
|
230a1d |
@@ -424,19 +446,9 @@ selinux_execve(int fd, const char *path,
|
|
|
230a1d |
debug_return;
|
|
|
230a1d |
}
|
|
|
230a1d |
|
|
|
230a1d |
- if (setexeccon(se_state.new_context)) {
|
|
|
230a1d |
- sudo_warn(U_("unable to set exec context to %s"), se_state.new_context);
|
|
|
230a1d |
- if (se_state.enforcing)
|
|
|
230a1d |
- debug_return;
|
|
|
230a1d |
- }
|
|
|
230a1d |
-
|
|
|
230a1d |
-#ifdef HAVE_SETKEYCREATECON
|
|
|
230a1d |
- if (setkeycreatecon(se_state.new_context)) {
|
|
|
230a1d |
- sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context);
|
|
|
230a1d |
- if (se_state.enforcing)
|
|
|
230a1d |
- debug_return;
|
|
|
230a1d |
- }
|
|
|
230a1d |
-#endif /* HAVE_SETKEYCREATECON */
|
|
|
230a1d |
+ /* Set SELinux exec and keycreate contexts. */
|
|
|
230a1d |
+ if (selinux_setcon() == -1)
|
|
|
230a1d |
+ debug_return;
|
|
|
230a1d |
|
|
|
230a1d |
/*
|
|
|
230a1d |
* Build new argv with sesh as argv[0].
|
|
|
230a1d |
diff -up ./src/sudo.c.symbolic-link-attack-3 ./src/sudo.c
|
|
|
230a1d |
--- ./src/sudo.c.symbolic-link-attack-3 2021-02-02 17:12:32.773182386 +0100
|
|
|
230a1d |
+++ ./src/sudo.c 2021-02-02 17:12:48.510964009 +0100
|
|
|
230a1d |
@@ -971,10 +971,6 @@ run_command(struct command_details *deta
|
|
|
230a1d |
case CMD_WSTATUS:
|
|
|
230a1d |
/* Command ran, exited or was killed. */
|
|
|
230a1d |
status = cstat.val;
|
|
|
230a1d |
-#ifdef HAVE_SELINUX
|
|
|
230a1d |
- if (ISSET(details->flags, CD_SUDOEDIT_COPY))
|
|
|
230a1d |
- break;
|
|
|
230a1d |
-#endif
|
|
|
230a1d |
sudo_debug_printf(SUDO_DEBUG_DEBUG,
|
|
|
230a1d |
"calling policy close with wait status %d", status);
|
|
|
230a1d |
policy_close(&policy_plugin, status, 0);
|
|
|
230a1d |
diff -up ./src/sudo_edit.c.symbolic-link-attack-3 ./src/sudo_edit.c
|
|
|
230a1d |
--- ./src/sudo_edit.c.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100
|
|
|
230a1d |
+++ ./src/sudo_edit.c 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -757,28 +757,54 @@ bad:
|
|
|
230a1d |
|
|
|
230a1d |
#ifdef HAVE_SELINUX
|
|
|
230a1d |
static int
|
|
|
230a1d |
+selinux_run_helper(char *argv[], char *envp[])
|
|
|
230a1d |
+{
|
|
|
230a1d |
+ int status, ret = SESH_ERR_FAILURE;
|
|
|
230a1d |
+ const char *sesh;
|
|
|
230a1d |
+ pid_t child, pid;
|
|
|
230a1d |
+ debug_decl(selinux_run_helper, SUDO_DEBUG_EDIT);
|
|
|
230a1d |
+
|
|
|
230a1d |
+ sesh = sudo_conf_sesh_path();
|
|
|
230a1d |
+ if (sesh == NULL) {
|
|
|
230a1d |
+ sudo_warnx("internal error: sesh path not set");
|
|
|
230a1d |
+ debug_return_int(-1);
|
|
|
230a1d |
+ }
|
|
|
230a1d |
+
|
|
|
230a1d |
+ child = sudo_debug_fork();
|
|
|
230a1d |
+ switch (child) {
|
|
|
230a1d |
+ case -1:
|
|
|
230a1d |
+ sudo_warn(U_("unable to fork"));
|
|
|
230a1d |
+ break;
|
|
|
230a1d |
+ case 0:
|
|
|
230a1d |
+ /* child runs sesh in new context */
|
|
|
230a1d |
+ if (selinux_setcon() == 0)
|
|
|
230a1d |
+ execve(sesh, argv, envp);
|
|
|
230a1d |
+ _exit(SESH_ERR_FAILURE);
|
|
|
230a1d |
+ default:
|
|
|
230a1d |
+ /* parent waits */
|
|
|
230a1d |
+ do {
|
|
|
230a1d |
+ pid = waitpid(child, &status, 0);
|
|
|
230a1d |
+ } while (pid == -1 && errno == EINTR);
|
|
|
230a1d |
+
|
|
|
230a1d |
+ ret = WIFSIGNALED(status) ? SESH_ERR_KILLED : WEXITSTATUS(status);
|
|
|
230a1d |
+ }
|
|
|
230a1d |
+
|
|
|
230a1d |
+ debug_return_int(ret);
|
|
|
230a1d |
+}
|
|
|
230a1d |
+
|
|
|
230a1d |
+static int
|
|
|
230a1d |
selinux_edit_create_tfiles(struct command_details *command_details,
|
|
|
230a1d |
struct tempfile *tf, char *files[], int nfiles)
|
|
|
230a1d |
{
|
|
|
230a1d |
char **sesh_args, **sesh_ap;
|
|
|
230a1d |
int i, rc, sesh_nargs;
|
|
|
230a1d |
struct stat sb;
|
|
|
230a1d |
- struct command_details saved_command_details;
|
|
|
230a1d |
debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT)
|
|
|
230a1d |
-
|
|
|
230a1d |
- /* Prepare selinux stuff (setexeccon) */
|
|
|
230a1d |
- if (selinux_setup(command_details->selinux_role,
|
|
|
230a1d |
- command_details->selinux_type, NULL, -1) != 0)
|
|
|
230a1d |
- debug_return_int(-1);
|
|
|
230a1d |
|
|
|
230a1d |
if (nfiles < 1)
|
|
|
230a1d |
debug_return_int(0);
|
|
|
230a1d |
|
|
|
230a1d |
/* Construct common args for sesh */
|
|
|
230a1d |
- memcpy(&saved_command_details, command_details, sizeof(struct command_details));
|
|
|
230a1d |
- command_details->command = _PATH_SUDO_SESH;
|
|
|
230a1d |
- command_details->flags |= CD_SUDOEDIT_COPY;
|
|
|
230a1d |
-
|
|
|
230a1d |
sesh_nargs = 4 + (nfiles * 2) + 1;
|
|
|
230a1d |
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
|
|
230a1d |
if (sesh_args == NULL) {
|
|
|
230a1d |
@@ -791,6 +817,7 @@ selinux_edit_create_tfiles(struct comman
|
|
|
230a1d |
*sesh_ap++ = "-h";
|
|
|
230a1d |
*sesh_ap++ = "0";
|
|
|
230a1d |
|
|
|
230a1d |
+ /* XXX - temp files should be created with user's context */
|
|
|
230a1d |
for (i = 0; i < nfiles; i++) {
|
|
|
230a1d |
char *tfile, *ofile = files[i];
|
|
|
230a1d |
int tfd;
|
|
|
230a1d |
@@ -820,8 +847,7 @@ selinux_edit_create_tfiles(struct comman
|
|
|
230a1d |
*sesh_ap = NULL;
|
|
|
230a1d |
|
|
|
230a1d |
/* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
|
|
|
230a1d |
- command_details->argv = sesh_args;
|
|
|
230a1d |
- rc = run_command(command_details);
|
|
|
230a1d |
+ rc = selinux_run_helper(sesh_args, command_details->envp);
|
|
|
230a1d |
switch (rc) {
|
|
|
230a1d |
case SESH_SUCCESS:
|
|
|
230a1d |
break;
|
|
|
230a1d |
@@ -829,15 +855,12 @@ selinux_edit_create_tfiles(struct comman
|
|
|
230a1d |
sudo_fatalx(U_("sesh: internal error: odd number of paths"));
|
|
|
230a1d |
case SESH_ERR_NO_FILES:
|
|
|
230a1d |
sudo_fatalx(U_("sesh: unable to create temporary files"));
|
|
|
230a1d |
+ case SESH_ERR_KILLED:
|
|
|
230a1d |
+ sudo_fatalx(U_("sesh: killed by a signal"));
|
|
|
230a1d |
default:
|
|
|
230a1d |
sudo_fatalx(U_("sesh: unknown error %d"), rc);
|
|
|
230a1d |
}
|
|
|
230a1d |
|
|
|
230a1d |
- /* Restore saved command_details. */
|
|
|
230a1d |
- command_details->command = saved_command_details.command;
|
|
|
230a1d |
- command_details->flags = saved_command_details.flags;
|
|
|
230a1d |
- command_details->argv = saved_command_details.argv;
|
|
|
230a1d |
-
|
|
|
230a1d |
/* Chown to user's UID so they can edit the temporary files. */
|
|
|
230a1d |
for (i = 0; i < nfiles; i++) {
|
|
|
230a1d |
if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) {
|
|
|
230a1d |
@@ -858,24 +881,14 @@ selinux_edit_copy_tfiles(struct command_
|
|
|
230a1d |
{
|
|
|
230a1d |
char **sesh_args, **sesh_ap;
|
|
|
230a1d |
int i, rc, sesh_nargs, ret = 1;
|
|
|
230a1d |
- struct command_details saved_command_details;
|
|
|
230a1d |
struct timespec ts;
|
|
|
230a1d |
struct stat sb;
|
|
|
230a1d |
debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT)
|
|
|
230a1d |
-
|
|
|
230a1d |
- /* Prepare selinux stuff (setexeccon) */
|
|
|
230a1d |
- if (selinux_setup(command_details->selinux_role,
|
|
|
230a1d |
- command_details->selinux_type, NULL, -1) != 0)
|
|
|
230a1d |
- debug_return_int(1);
|
|
|
230a1d |
|
|
|
230a1d |
if (nfiles < 1)
|
|
|
230a1d |
debug_return_int(0);
|
|
|
230a1d |
|
|
|
230a1d |
/* Construct common args for sesh */
|
|
|
230a1d |
- memcpy(&saved_command_details, command_details, sizeof(struct command_details));
|
|
|
230a1d |
- command_details->command = _PATH_SUDO_SESH;
|
|
|
230a1d |
- command_details->flags |= CD_SUDOEDIT_COPY;
|
|
|
230a1d |
-
|
|
|
230a1d |
sesh_nargs = 3 + (nfiles * 2) + 1;
|
|
|
230a1d |
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
|
|
230a1d |
if (sesh_args == NULL) {
|
|
|
230a1d |
@@ -913,32 +926,29 @@ selinux_edit_copy_tfiles(struct command_
|
|
|
230a1d |
|
|
|
230a1d |
if (sesh_ap - sesh_args > 3) {
|
|
|
230a1d |
/* Run sesh -e 1 <t1> <o1> ... <tn> <on> */
|
|
|
230a1d |
- command_details->argv = sesh_args;
|
|
|
230a1d |
- rc = run_command(command_details);
|
|
|
230a1d |
+ rc = selinux_run_helper(sesh_args, command_details->envp);
|
|
|
230a1d |
switch (rc) {
|
|
|
230a1d |
case SESH_SUCCESS:
|
|
|
230a1d |
ret = 0;
|
|
|
230a1d |
break;
|
|
|
230a1d |
case SESH_ERR_NO_FILES:
|
|
|
230a1d |
sudo_warnx(U_("unable to copy temporary files back to their original location"));
|
|
|
230a1d |
- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
|
|
230a1d |
break;
|
|
|
230a1d |
case SESH_ERR_SOME_FILES:
|
|
|
230a1d |
sudo_warnx(U_("unable to copy some of the temporary files back to their original location"));
|
|
|
230a1d |
- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
|
|
230a1d |
+ break;
|
|
|
230a1d |
+ case SESH_ERR_KILLED:
|
|
|
230a1d |
+ sudo_warnx(U_("sesh: killed by a signal"));
|
|
|
230a1d |
break;
|
|
|
230a1d |
default:
|
|
|
230a1d |
sudo_warnx(U_("sesh: unknown error %d"), rc);
|
|
|
230a1d |
break;
|
|
|
230a1d |
}
|
|
|
230a1d |
+ if (ret != 0)
|
|
|
230a1d |
+ sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
|
|
230a1d |
}
|
|
|
230a1d |
free(sesh_args);
|
|
|
230a1d |
|
|
|
230a1d |
- /* Restore saved command_details. */
|
|
|
230a1d |
- command_details->command = saved_command_details.command;
|
|
|
230a1d |
- command_details->flags = saved_command_details.flags;
|
|
|
230a1d |
- command_details->argv = saved_command_details.argv;
|
|
|
230a1d |
-
|
|
|
230a1d |
debug_return_int(ret);
|
|
|
230a1d |
}
|
|
|
230a1d |
#endif /* HAVE_SELINUX */
|
|
|
230a1d |
@@ -990,6 +1000,15 @@ sudo_edit(struct command_details *comman
|
|
|
230a1d |
goto cleanup;
|
|
|
230a1d |
}
|
|
|
230a1d |
|
|
|
230a1d |
+#ifdef HAVE_SELINUX
|
|
|
230a1d |
+ /* Compute new SELinux security context. */
|
|
|
230a1d |
+ if (ISSET(command_details->flags, CD_RBAC_ENABLED)) {
|
|
|
230a1d |
+ if (selinux_setup(command_details->selinux_role,
|
|
|
230a1d |
+ command_details->selinux_type, NULL, -1, false) != 0)
|
|
|
230a1d |
+ goto cleanup;
|
|
|
230a1d |
+ }
|
|
|
230a1d |
+#endif
|
|
|
230a1d |
+
|
|
|
230a1d |
/* Copy editor files to temporaries. */
|
|
|
230a1d |
tf = calloc(nfiles, sizeof(*tf));
|
|
|
230a1d |
if (tf == NULL) {
|
|
|
230a1d |
@@ -1025,6 +1044,7 @@ sudo_edit(struct command_details *comman
|
|
|
230a1d |
/*
|
|
|
230a1d |
* Run the editor with the invoking user's creds,
|
|
|
230a1d |
* keeping track of the time spent in the editor.
|
|
|
230a1d |
+ * XXX - should run editor with user's context
|
|
|
230a1d |
*/
|
|
|
230a1d |
if (sudo_gettime_real(×[0]) == -1) {
|
|
|
230a1d |
sudo_warn(U_("unable to read the clock"));
|
|
|
230a1d |
diff -up ./src/sudo_exec.h.symbolic-link-attack-3 ./src/sudo_exec.h
|
|
|
230a1d |
--- ./src/sudo_exec.h.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100
|
|
|
230a1d |
+++ ./src/sudo_exec.h 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -73,6 +73,7 @@
|
|
|
230a1d |
*/
|
|
|
230a1d |
#define SESH_SUCCESS 0 /* successful operation */
|
|
|
230a1d |
#define SESH_ERR_FAILURE 1 /* unspecified error */
|
|
|
230a1d |
+#define SESH_ERR_KILLED 2 /* killed by a signal */
|
|
|
230a1d |
#define SESH_ERR_INVALID 30 /* invalid -e arg value */
|
|
|
230a1d |
#define SESH_ERR_BAD_PATHS 31 /* odd number of paths */
|
|
|
230a1d |
#define SESH_ERR_NO_FILES 32 /* copy error, no files copied */
|
|
|
230a1d |
diff -up ./src/sudo.h.symbolic-link-attack-3 ./src/sudo.h
|
|
|
230a1d |
--- ./src/sudo.h.symbolic-link-attack-3 2019-10-28 13:28:52.000000000 +0100
|
|
|
230a1d |
+++ ./src/sudo.h 2021-02-02 17:11:32.382020407 +0100
|
|
|
230a1d |
@@ -135,12 +135,11 @@ struct user_details {
|
|
|
230a1d |
#define CD_USE_PTY 0x001000
|
|
|
230a1d |
#define CD_SET_UTMP 0x002000
|
|
|
230a1d |
#define CD_EXEC_BG 0x004000
|
|
|
230a1d |
-#define CD_SUDOEDIT_COPY 0x008000
|
|
|
230a1d |
-#define CD_SUDOEDIT_FOLLOW 0x010000
|
|
|
230a1d |
-#define CD_SUDOEDIT_CHECKDIR 0x020000
|
|
|
230a1d |
-#define CD_SET_GROUPS 0x040000
|
|
|
230a1d |
-#define CD_LOGIN_SHELL 0x080000
|
|
|
230a1d |
-#define CD_OVERRIDE_UMASK 0x100000
|
|
|
230a1d |
+#define CD_SUDOEDIT_FOLLOW 0x008000
|
|
|
230a1d |
+#define CD_SUDOEDIT_CHECKDIR 0x010000
|
|
|
230a1d |
+#define CD_SET_GROUPS 0x020000
|
|
|
230a1d |
+#define CD_LOGIN_SHELL 0x040000
|
|
|
230a1d |
+#define CD_OVERRIDE_UMASK 0x080000
|
|
|
230a1d |
|
|
|
230a1d |
struct preserved_fd {
|
|
|
230a1d |
TAILQ_ENTRY(preserved_fd) entries;
|
|
|
230a1d |
@@ -240,7 +239,8 @@ int os_init_openbsd(int argc, char *argv
|
|
|
230a1d |
/* selinux.c */
|
|
|
230a1d |
int selinux_restore_tty(void);
|
|
|
230a1d |
int selinux_setup(const char *role, const char *type, const char *ttyn,
|
|
|
230a1d |
- int ttyfd);
|
|
|
230a1d |
+ int ttyfd, bool label_tty);
|
|
|
230a1d |
+int selinux_setcon(void);
|
|
|
230a1d |
void selinux_execve(int fd, const char *path, char *const argv[],
|
|
|
230a1d |
char *envp[], bool noexec);
|
|
|
230a1d |
|