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:
@@ -17,7 +17,7 @@
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.nr SL @SEMAN@
|
||||
.TH "SUDO.CONF" "@mansectform@" "September 1, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.TH "SUDO.CONF" "@mansectform@" "September 7, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.nh
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@@ -290,9 +290,14 @@ macOS and Solaris.
|
||||
intercept
|
||||
.br
|
||||
The fully-qualified path to a shared library containing a wrappers for the
|
||||
\fBexecv\fR()
|
||||
\fBexecl\fR(),
|
||||
\fBexecle\fR(),
|
||||
\fBexeclp\fR(),
|
||||
\fBexecv\fR(),
|
||||
\fBexecve\fR(),
|
||||
\fBexecvp\fR(),
|
||||
and
|
||||
\fBexecve\fR()
|
||||
\fBexecvpe\fR()
|
||||
library functions that intercepts attempts to run further commands and
|
||||
performs a policy check before allowing them to be executed.
|
||||
This is used to implement the
|
||||
|
@@ -16,7 +16,7 @@
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.nr SL @SEMAN@
|
||||
.Dd September 1, 2021
|
||||
.Dd September 7, 2021
|
||||
.Dt SUDO.CONF @mansectform@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@@ -265,9 +265,14 @@ functions, for example
|
||||
macOS and Solaris.
|
||||
.It intercept
|
||||
The fully-qualified path to a shared library containing a wrappers for the
|
||||
.Fn execv
|
||||
.Fn execl ,
|
||||
.Fn execle ,
|
||||
.Fn execlp ,
|
||||
.Fn execv ,
|
||||
.Fn execve ,
|
||||
.Fn execvp ,
|
||||
and
|
||||
.Fn execve
|
||||
.Fn execvpe
|
||||
library functions that intercepts attempts to run further commands and
|
||||
performs a policy check before allowing them to be executed.
|
||||
This is used to implement the
|
||||
|
@@ -25,7 +25,7 @@
|
||||
.nr BA @BAMAN@
|
||||
.nr LC @LCMAN@
|
||||
.nr PS @PSMAN@
|
||||
.TH "SUDOERS" "@mansectform@" "September 3, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.TH "SUDOERS" "@mansectform@" "September 7, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.nh
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@@ -2860,9 +2860,14 @@ If set,
|
||||
\fBsudoers\fR
|
||||
will log when a command spawns a child process and executes a program
|
||||
using the
|
||||
\fBexecv\fR()
|
||||
\fBexecl\fR(),
|
||||
\fBexecle\fR(),
|
||||
\fBexeclp\fR(),
|
||||
\fBexecv\fR(),
|
||||
\fBexecve\fR(),
|
||||
\fBexecvp\fR(),
|
||||
or
|
||||
\fBexecve\fR()
|
||||
\fBexecvpe\fR()
|
||||
library functions.
|
||||
For example, if a shell is run by
|
||||
\fBsudo\fR,
|
||||
@@ -6331,9 +6336,14 @@ Currently,
|
||||
\fBsudo\fR's
|
||||
\fIintercept\fR
|
||||
functionality only works for programs that use the
|
||||
\fBexecv\fR()
|
||||
and
|
||||
\fBexecve\fR()
|
||||
\fBexecl\fR(),
|
||||
\fBexecle\fR(),
|
||||
\fBexeclp\fR(),
|
||||
\fBexecv\fR(),
|
||||
\fBexecve\fR(),
|
||||
\fBexecvp\fR(),
|
||||
or
|
||||
\fBexecvpe\fR()
|
||||
library functions to run the new command.
|
||||
This may be expanded in a future release of
|
||||
\fBsudo\fR.
|
||||
|
@@ -24,7 +24,7 @@
|
||||
.nr BA @BAMAN@
|
||||
.nr LC @LCMAN@
|
||||
.nr PS @PSMAN@
|
||||
.Dd September 3, 2021
|
||||
.Dd September 7, 2021
|
||||
.Dt SUDOERS @mansectform@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@@ -2692,9 +2692,14 @@ If set,
|
||||
.Nm
|
||||
will log when a command spawns a child process and executes a program
|
||||
using the
|
||||
.Fn execv
|
||||
.Fn execl ,
|
||||
.Fn execle ,
|
||||
.Fn execlp ,
|
||||
.Fn execv ,
|
||||
.Fn execve ,
|
||||
.Fn execvp ,
|
||||
or
|
||||
.Fn execve
|
||||
.Fn execvpe
|
||||
library functions.
|
||||
For example, if a shell is run by
|
||||
.Nm sudo ,
|
||||
@@ -5852,9 +5857,14 @@ Currently,
|
||||
.Nm sudo Ns 's
|
||||
.Em intercept
|
||||
functionality only works for programs that use the
|
||||
.Fn execv
|
||||
and
|
||||
.Fn execve
|
||||
.Fn execl ,
|
||||
.Fn execle ,
|
||||
.Fn execlp ,
|
||||
.Fn execv ,
|
||||
.Fn execve ,
|
||||
.Fn execvp ,
|
||||
or
|
||||
.Fn execvpe
|
||||
library functions to run the new command.
|
||||
This may be expanded in a future release of
|
||||
.Nm sudo .
|
||||
|
@@ -1,2 +1,7 @@
|
||||
execl
|
||||
execle
|
||||
execlp
|
||||
execv
|
||||
execve
|
||||
execvp
|
||||
execvpe
|
||||
|
@@ -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