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->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
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
|
23
src/sesh.c
23
src/sesh.c
@@ -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);
|
||||||
|
12
src/sudo.c
12
src/sudo.c
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user