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:
22
src/exec.c
22
src/exec.c
@@ -229,13 +229,19 @@ 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) {
|
||||
/* 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)
|
||||
goto done;
|
||||
if (details->chroot != NULL)
|
||||
sudo_warnx(U_("starting from %s"), "/");
|
||||
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 (!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
|
||||
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
|
||||
{
|
||||
|
@@ -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;
|
||||
|
23
src/sesh.c
23
src/sesh.c
@@ -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);
|
||||
|
12
src/sudo.c
12
src/sudo.c
@@ -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);
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user