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

View File

@@ -1,7 +1,7 @@
/*
* 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>
*
* Borrowed heavily from newrole source code
@@ -440,7 +440,7 @@ selinux_setexeccon(void)
void
selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
int flags)
const char *rundir, int flags)
{
char **nargv;
const char *sesh;
@@ -470,7 +470,7 @@ selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
errno = EINVAL;
debug_return;
}
nargv = reallocarray(NULL, argc + 3, sizeof(char *));
nargv = reallocarray(NULL, argc + 4, sizeof(char *));
if (nargv == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
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");
}
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) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return;

View File

@@ -94,11 +94,30 @@ main(int argc, char *argv[], char *envp[])
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 (strncmp(argv[1], "--execfd=", 9) == 0) {
if (strncmp(argv[1], "--execfd=", sizeof("--execfd=") - 1) == 0) {
const char *errstr;
cp = argv[1] + 9;
cp = argv[1] + sizeof("--execfd=") - 1;
fd = sudo_strtonum(cp, 0, INT_MAX, &errstr);
if (errstr != NULL)
sudo_fatalx(U_("invalid file descriptor number: %s"), cp);

View File

@@ -1,7 +1,7 @@
/*
* 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
* 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("command=", command)
SET_STRING("cwd=", cwd)
if (strncmp("cwd_optional=", info[i], sizeof("cwd_optional=") - 1) == 0) {
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;
}
SET_FLAG("cwd_optional=", CD_CWD_OPTIONAL)
if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
cp = info[i] + sizeof("closefrom=") - 1;
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_FEXECVE 0x00800000
#define CD_INTERCEPT_VERIFY 0x01000000
#define CD_RBAC_SET_CWD 0x02000000
#define CD_CWD_OPTIONAL 0x04000000
struct preserved_fd {
TAILQ_ENTRY(preserved_fd) entries;
@@ -191,7 +193,6 @@ struct command_details {
int closefrom;
int flags;
int execfd;
int cwd_optional;
struct preserved_fd_list preserved_fds;
struct passwd *pw;
const char *command;
@@ -287,7 +288,7 @@ int selinux_relabel_tty(const char *ttyn, int ttyfd);
int selinux_restore_tty(void);
int selinux_setexeccon(void);
void selinux_execve(int fd, const char *path, char *const argv[],
char *envp[], int flags);
char *envp[], const char *rundir, int flags);
/* apparmor.c */
int apparmor_is_enabled(void);