Add support for execl, execle, execlp, execvp, and execvpe.
Currently, PATH traversal is handled by sudoers which uses the original PATH, not the one updated by the shell.
This commit is contained in:
@@ -48,9 +48,104 @@
|
||||
#include "sudo_util.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
/* execl flavors */
|
||||
#define SUDO_EXECL 0x0
|
||||
#define SUDO_EXECLE 0x1
|
||||
#define SUDO_EXECLP 0x2
|
||||
|
||||
extern char **environ;
|
||||
extern bool command_allowed(const char *cmnd, char * const argv[], char * const envp[], char **ncmnd, char ***nargv, char ***nenvp);
|
||||
|
||||
typedef int (*sudo_fn_execve_t)(const char *, char *const *, char *const *);
|
||||
|
||||
static int
|
||||
exec_wrapper(const char *cmnd, char * const argv[], char * const envp[],
|
||||
bool is_execvp)
|
||||
{
|
||||
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
|
||||
void *fn = NULL;
|
||||
debug_decl(exec_wrapper, SUDO_DEBUG_EXEC);
|
||||
|
||||
/* Only check PATH for the command for execlp/execvp/execvpe. */
|
||||
if (!is_execvp && strchr(cmnd, '/') == NULL) {
|
||||
errno = ENOENT;
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
# if defined(HAVE___INTERPOSE)
|
||||
fn = execve;
|
||||
# elif defined(HAVE_DLOPEN)
|
||||
fn = dlsym(RTLD_NEXT, "execve");
|
||||
# elif defined(HAVE_SHL_LOAD)
|
||||
fn = sudo_shl_get_next("execve", TYPE_PROCEDURE);
|
||||
# endif
|
||||
if (fn == NULL) {
|
||||
errno = EACCES;
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
if (command_allowed(cmnd, argv, envp, &ncmnd, &nargv, &nenvp)) {
|
||||
/* Execute the command using the "real" execve() function. */
|
||||
((sudo_fn_execve_t)fn)(ncmnd, nargv, nenvp);
|
||||
|
||||
/* Fall back to exec via shell for execvp and friends. */
|
||||
if (errno == ENOEXEC && is_execvp) {
|
||||
int argc;
|
||||
char **shargv;
|
||||
|
||||
for (argc = 0; argv[argc] != NULL; argc++)
|
||||
continue;
|
||||
shargv = reallocarray(NULL, (argc + 2), sizeof(char *));
|
||||
if (shargv == NULL)
|
||||
return -1;
|
||||
shargv[0] = "sh";
|
||||
shargv[1] = ncmnd;
|
||||
memcpy(shargv + 2, nargv + 1, argc * sizeof(char *));
|
||||
((sudo_fn_execve_t)fn)(_PATH_SUDO_BSHELL, shargv, nenvp);
|
||||
free(shargv);
|
||||
}
|
||||
} else {
|
||||
errno = EACCES;
|
||||
}
|
||||
if (ncmnd != cmnd)
|
||||
free(ncmnd);
|
||||
if (nargv != argv)
|
||||
free(nargv);
|
||||
if (nenvp != envp)
|
||||
free(nenvp);
|
||||
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
static int
|
||||
execl_wrapper(int type, const char *name, const char *arg, va_list ap)
|
||||
{
|
||||
char **argv, **envp = environ;
|
||||
int argc = 1;
|
||||
va_list ap2;
|
||||
debug_decl(execl_wrapper, SUDO_DEBUG_EXEC);
|
||||
|
||||
va_copy(ap2, ap);
|
||||
while (va_arg(ap2, char *) != NULL)
|
||||
argc++;
|
||||
va_end(ap2);
|
||||
argv = reallocarray(NULL, (argc + 1), sizeof(char *));
|
||||
if (argv == NULL)
|
||||
debug_return_int(-1);
|
||||
|
||||
argc = 0;
|
||||
argv[argc++] = (char *)arg;
|
||||
while ((argv[argc] = va_arg(ap, char *)) != NULL)
|
||||
argc++;
|
||||
if (type == SUDO_EXECLE)
|
||||
envp = va_arg(ap, char **);
|
||||
|
||||
exec_wrapper(name, argv, envp, type == SUDO_EXECLP);
|
||||
free(argv);
|
||||
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
#ifdef HAVE___INTERPOSE
|
||||
/*
|
||||
* Mac OS X 10.4 and above has support for library symbol interposition.
|
||||
@@ -64,41 +159,77 @@ typedef struct interpose_s {
|
||||
static int
|
||||
my_execve(const char *cmnd, char * const argv[], char * const envp[])
|
||||
{
|
||||
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
|
||||
|
||||
if (command_allowed(cmnd, argv, envp, &ncmnd, &nargv, &nenvp)) {
|
||||
/* Execute the command using the "real" execve() function. */
|
||||
execve(ncmnd, nargv, nenvp);
|
||||
} else {
|
||||
errno = EACCES;
|
||||
}
|
||||
if (ncmnd != cmnd)
|
||||
free(ncmnd);
|
||||
if (nargv != argv)
|
||||
free(nargv);
|
||||
if (nenvp != envp)
|
||||
free(nenvp);
|
||||
|
||||
return -1;
|
||||
return exec_wrapper(cmnd, argv, environ, false);
|
||||
}
|
||||
|
||||
static int
|
||||
my_execv(const char *cmnd, char * const argv[])
|
||||
{
|
||||
return my_execve(cmnd, argv, environ);
|
||||
return execve(cmnd, argv, environ);
|
||||
}
|
||||
|
||||
static int
|
||||
my_execvpe(const char *cmnd, char * const argv[], char * const envp[])
|
||||
{
|
||||
return exec_wrapper(cmnd, argv, envp, true);
|
||||
}
|
||||
|
||||
static int
|
||||
my_execvp(const char *cmnd, char * const argv[])
|
||||
{
|
||||
return exec_wrapper(cmnd, argv, environ, true);
|
||||
}
|
||||
|
||||
static int
|
||||
my_execl(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECL, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
my_execle(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECLE, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
my_execlp(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECLP, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Magic to tell dyld to do symbol interposition. */
|
||||
__attribute__((__used__)) static const interpose_t interposers[]
|
||||
__attribute__((__section__("__DATA,__interpose"))) = {
|
||||
{ (void *)my_execl, (void *)execl },
|
||||
{ (void *)my_execle, (void *)execle },
|
||||
{ (void *)my_execlp, (void *)execlp },
|
||||
{ (void *)my_execv, (void *)execv },
|
||||
{ (void *)my_execve, (void *)execve },
|
||||
{ (void *)my_execv, (void *)execv }
|
||||
{ (void *)my_execvp, (void *)execvp },
|
||||
{ (void *)my_execvpe, (void *)execvpe }
|
||||
};
|
||||
|
||||
#else /* HAVE___INTERPOSE */
|
||||
|
||||
typedef int (*sudo_fn_execve_t)(const char *, char *const *, char *const *);
|
||||
|
||||
# if defined(HAVE_SHL_LOAD)
|
||||
static void *
|
||||
sudo_shl_get_next(const char *symbol, short type)
|
||||
@@ -127,34 +258,7 @@ sudo_shl_get_next(const char *symbol, short type)
|
||||
sudo_dso_public int
|
||||
execve(const char *cmnd, char * const argv[], char * const envp[])
|
||||
{
|
||||
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
|
||||
void *fn = NULL;
|
||||
debug_decl(execve, SUDO_DEBUG_EXEC);
|
||||
|
||||
# if defined(HAVE_DLOPEN)
|
||||
fn = dlsym(RTLD_NEXT, "execve");
|
||||
# elif defined(HAVE_SHL_LOAD)
|
||||
fn = sudo_shl_get_next("execve", TYPE_PROCEDURE);
|
||||
# endif
|
||||
if (fn == NULL) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (command_allowed(cmnd, argv, envp, &ncmnd, &nargv, &nenvp)) {
|
||||
/* Execute the command using the "real" execve() function. */
|
||||
return ((sudo_fn_execve_t)fn)(ncmnd, nargv, nenvp);
|
||||
} else {
|
||||
errno = EACCES;
|
||||
}
|
||||
if (ncmnd != cmnd)
|
||||
free(ncmnd);
|
||||
if (nargv != argv)
|
||||
free(nargv);
|
||||
if (nenvp != envp)
|
||||
free(nenvp);
|
||||
|
||||
return -1;
|
||||
return exec_wrapper(cmnd, argv, environ, false);
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
@@ -162,4 +266,52 @@ execv(const char *cmnd, char * const argv[])
|
||||
{
|
||||
return execve(cmnd, argv, environ);
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
execvpe(const char *cmnd, char * const argv[], char * const envp[])
|
||||
{
|
||||
return exec_wrapper(cmnd, argv, envp, true);
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
execvp(const char *cmnd, char * const argv[])
|
||||
{
|
||||
return exec_wrapper(cmnd, argv, environ, true);
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
execl(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECL, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
execle(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECLE, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sudo_dso_public int
|
||||
execlp(const char *name, const char *arg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, arg);
|
||||
execl_wrapper(SUDO_EXECLP, name, arg, ap);
|
||||
va_end(ap);
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif /* HAVE___INTERPOSE) */
|
||||
|
Reference in New Issue
Block a user