Defer chdir(2) until sesh when running with SELinux.

We need to be running with the correct security context or the
chdir(2) may fail.  GitHub issue #160.
This commit is contained in:
Todd C. Miller
2022-08-01 13:40:47 -06:00
parent 555474d3aa
commit cf250354fc
5 changed files with 55 additions and 25 deletions

View File

@@ -229,13 +229,19 @@ exec_setup(struct command_details *details, int intercept_fd, int errfd)
if (details->cwd != NULL) { if (details->cwd != NULL) {
if (details->chroot != NULL || user_details.cwd == NULL || if (details->chroot != NULL || user_details.cwd == NULL ||
strcmp(details->cwd, user_details.cwd) != 0) { strcmp(details->cwd, user_details.cwd) != 0) {
/* Note: cwd is relative to the new root, if any. */ if (ISSET(details->flags, CD_RBAC_ENABLED)) {
if (chdir(details->cwd) == -1) { /* For SELinux, chdir(2) in sesh after the context change. */
sudo_warn(U_("unable to change directory to %s"), details->cwd); SET(details->flags, CD_RBAC_SET_CWD);
if (!details->cwd_optional) } else {
goto done; /* Note: cwd is relative to the new root, if any. */
if (details->chroot != NULL) if (chdir(details->cwd) == -1) {
sudo_warnx(U_("starting from %s"), "/"); sudo_warn(U_("unable to change directory to %s"),
details->cwd);
if (!ISSET(details->flags, CD_CWD_OPTIONAL))
goto done;
if (details->chroot != NULL)
sudo_warnx(U_("starting from %s"), "/");
}
} }
} }
} }
@@ -288,7 +294,7 @@ exec_cmnd(struct command_details *details, sigset_t *mask,
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (ISSET(details->flags, CD_RBAC_ENABLED)) { if (ISSET(details->flags, CD_RBAC_ENABLED)) {
selinux_execve(details->execfd, details->command, details->argv, selinux_execve(details->execfd, details->command, details->argv,
details->envp, details->flags); details->envp, details->cwd, details->flags);
} else } else
#endif #endif
{ {

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws>
* Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com> * Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com>
* *
* Borrowed heavily from newrole source code * Borrowed heavily from newrole source code
@@ -440,7 +440,7 @@ selinux_setexeccon(void)
void void
selinux_execve(int fd, const char *path, char *const argv[], char *envp[], selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
int flags) const char *rundir, int flags)
{ {
char **nargv; char **nargv;
const char *sesh; const char *sesh;
@@ -470,7 +470,7 @@ selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
errno = EINVAL; errno = EINVAL;
debug_return; debug_return;
} }
nargv = reallocarray(NULL, argc + 3, sizeof(char *)); nargv = reallocarray(NULL, argc + 4, sizeof(char *));
if (nargv == NULL) { if (nargv == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return; debug_return;
@@ -484,6 +484,18 @@ selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
nargv[0] = (char *)(login_shell ? "-sesh" : "sesh"); nargv[0] = (char *)(login_shell ? "-sesh" : "sesh");
} }
nargc = 1; nargc = 1;
if (ISSET(flags, CD_RBAC_SET_CWD)) {
const char *prefix = ISSET(flags, CD_CWD_OPTIONAL) ? "+" : "";
if (rundir == NULL) {
sudo_warnx("internal error: sesh rundir not set");
errno = EINVAL;
debug_return;
}
if (asprintf(&nargv[nargc++], "--chdir=%s%s", prefix, rundir) == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return;
}
}
if (fd != -1 && asprintf(&nargv[nargc++], "--execfd=%d", fd) == -1) { if (fd != -1 && asprintf(&nargv[nargc++], "--execfd=%d", fd) == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return; debug_return;

View File

@@ -94,11 +94,30 @@ main(int argc, char *argv[], char *envp[])
SET(flags, CD_NOEXEC); SET(flags, CD_NOEXEC);
} }
/* If argv[1] is --chdir=dir, change to specified dir. */
if (strncmp(argv[1], "--chdir=", sizeof("--chdir=") - 1) == 0) {
const char *cp = argv[1] + sizeof("--chdir=") - 1;
bool cwd_optional = false;
/* If run dir starts with a '+', ignore chdir(2) failure. */
if (*cp == '+') {
cwd_optional = true;
cp++;
}
if (chdir(cp) == -1) {
sudo_warnx(U_("unable to change directory to %s"), cp);
if (!cwd_optional)
exit(EXIT_FAILURE);
}
argv++;
argc--;
}
/* If argv[1] is --execfd=%d, extract the fd to exec with. */ /* If argv[1] is --execfd=%d, extract the fd to exec with. */
if (strncmp(argv[1], "--execfd=", 9) == 0) { if (strncmp(argv[1], "--execfd=", sizeof("--execfd=") - 1) == 0) {
const char *errstr; const char *errstr;
cp = argv[1] + 9; cp = argv[1] + sizeof("--execfd=") - 1;
fd = sudo_strtonum(cp, 0, INT_MAX, &errstr); fd = sudo_strtonum(cp, 0, INT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
sudo_fatalx(U_("invalid file descriptor number: %s"), cp); sudo_fatalx(U_("invalid file descriptor number: %s"), cp);

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -696,15 +696,7 @@ command_info_to_details(char * const info[], struct command_details *details)
SET_STRING("chroot=", chroot) SET_STRING("chroot=", chroot)
SET_STRING("command=", command) SET_STRING("command=", command)
SET_STRING("cwd=", cwd) SET_STRING("cwd=", cwd)
if (strncmp("cwd_optional=", info[i], sizeof("cwd_optional=") - 1) == 0) { SET_FLAG("cwd_optional=", CD_CWD_OPTIONAL)
cp = info[i] + sizeof("cwd_optional=") - 1;
details->cwd_optional = sudo_strtobool(cp);
if (details->cwd_optional == -1) {
errno = EINVAL;
sudo_fatal("%s", info[i]);
}
break;
}
if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
cp = info[i] + sizeof("closefrom=") - 1; cp = info[i] + sizeof("closefrom=") - 1;
details->closefrom = sudo_strtonum(cp, 0, INT_MAX, &errstr); details->closefrom = sudo_strtonum(cp, 0, INT_MAX, &errstr);

View File

@@ -174,6 +174,8 @@ struct user_details {
#define CD_USE_PTRACE 0x00400000 #define CD_USE_PTRACE 0x00400000
#define CD_FEXECVE 0x00800000 #define CD_FEXECVE 0x00800000
#define CD_INTERCEPT_VERIFY 0x01000000 #define CD_INTERCEPT_VERIFY 0x01000000
#define CD_RBAC_SET_CWD 0x02000000
#define CD_CWD_OPTIONAL 0x04000000
struct preserved_fd { struct preserved_fd {
TAILQ_ENTRY(preserved_fd) entries; TAILQ_ENTRY(preserved_fd) entries;
@@ -191,7 +193,6 @@ struct command_details {
int closefrom; int closefrom;
int flags; int flags;
int execfd; int execfd;
int cwd_optional;
struct preserved_fd_list preserved_fds; struct preserved_fd_list preserved_fds;
struct passwd *pw; struct passwd *pw;
const char *command; const char *command;
@@ -287,7 +288,7 @@ int selinux_relabel_tty(const char *ttyn, int ttyfd);
int selinux_restore_tty(void); int selinux_restore_tty(void);
int selinux_setexeccon(void); int selinux_setexeccon(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[], int flags); char *envp[], const char *rundir, int flags);
/* apparmor.c */ /* apparmor.c */
int apparmor_is_enabled(void); int apparmor_is_enabled(void);