Add support for intercepting the system(3) function.

This also means we can log system(3) with log_subcmds.
This commit is contained in:
Todd C. Miller
2022-05-31 14:45:00 -06:00
parent 436deda08d
commit f52342031d
6 changed files with 105 additions and 14 deletions

View File

@@ -17,7 +17,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.nr SL @SEMAN@ .nr SL @SEMAN@
.TH "SUDO.CONF" "@mansectform@" "April 28, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDO.CONF" "@mansectform@" "May 31, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -296,8 +296,9 @@ The fully-qualified path to a shared library containing a wrappers for the
\fBexecv\fR(), \fBexecv\fR(),
\fBexecve\fR(), \fBexecve\fR(),
\fBexecvp\fR(), \fBexecvp\fR(),
\fBexecvpe\fR(),
and and
\fBexecvpe\fR() \fBsystem\fR()
library functions that intercepts attempts to run further commands and library functions that intercepts attempts to run further commands and
performs a policy check before allowing them to be executed. performs a policy check before allowing them to be executed.
This is used to implement the This is used to implement the

View File

@@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.nr SL @SEMAN@ .nr SL @SEMAN@
.Dd April 28, 2022 .Dd May 31, 2022
.Dt SUDO.CONF @mansectform@ .Dt SUDO.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -271,8 +271,9 @@ The fully-qualified path to a shared library containing a wrappers for the
.Fn execv , .Fn execv ,
.Fn execve , .Fn execve ,
.Fn execvp , .Fn execvp ,
.Fn execvpe ,
and and
.Fn execvpe .Fn system
library functions that intercepts attempts to run further commands and library functions that intercepts attempts to run further commands and
performs a policy check before allowing them to be executed. performs a policy check before allowing them to be executed.
This is used to implement the This is used to implement the

View File

@@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.TH "SUDOERS" "@mansectform@" "May 24, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDOERS" "@mansectform@" "May 31, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -3151,8 +3151,9 @@ using the
\fBexecv\fR(), \fBexecv\fR(),
\fBexecve\fR(), \fBexecve\fR(),
\fBexecvp\fR(), \fBexecvp\fR(),
\fBexecvpe\fR(),
or or
\fBexecvpe\fR() \fBsystem\fR()
library functions. library functions.
For example, if a shell is run by For example, if a shell is run by
\fBsudo\fR, \fBsudo\fR,
@@ -4305,8 +4306,9 @@ Preload a dynamic shared object (shared library) that intercepts the
\fBexecv\fR(), \fBexecv\fR(),
\fBexecve\fR(), \fBexecve\fR(),
\fBexecvp\fR(), \fBexecvp\fR(),
\fBexecvpe\fR(),
and and
\fBexecvpe\fR() \fBsystem\fR()
library functions. library functions.
A value of A value of
\fIdso\fR \fIdso\fR
@@ -6929,8 +6931,9 @@ functionality only works for programs that use the
\fBexecv\fR(), \fBexecv\fR(),
\fBexecve\fR(), \fBexecve\fR(),
\fBexecvp\fR(), \fBexecvp\fR(),
\fBexecvpe\fR(),
or or
\fBexecvpe\fR() \fBsystem\fR()
library functions to run the new command. library functions to run the new command.
This may be expanded in a future release of This may be expanded in a future release of
\fBsudo\fR. \fBsudo\fR.

View File

@@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.Dd May 24, 2022 .Dd May 31, 2022
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -2985,8 +2985,9 @@ using the
.Fn execv , .Fn execv ,
.Fn execve , .Fn execve ,
.Fn execvp , .Fn execvp ,
.Fn execvpe ,
or or
.Fn execvpe .Fn system
library functions. library functions.
For example, if a shell is run by For example, if a shell is run by
.Nm sudo , .Nm sudo ,
@@ -4077,8 +4078,9 @@ Preload a dynamic shared object (shared library) that intercepts the
.Fn execv , .Fn execv ,
.Fn execve , .Fn execve ,
.Fn execvp , .Fn execvp ,
.Fn execvpe ,
and and
.Fn execvpe .Fn system
library functions. library functions.
A value of A value of
.Em dso .Em dso
@@ -6420,8 +6422,9 @@ functionality only works for programs that use the
.Fn execv , .Fn execv ,
.Fn execve , .Fn execve ,
.Fn execvp , .Fn execvp ,
.Fn execvpe ,
or or
.Fn execvpe .Fn system
library functions to run the new command. library functions to run the new command.
This may be expanded in a future release of This may be expanded in a future release of
.Nm sudo . .Nm sudo .

View File

@@ -4,3 +4,4 @@ execlp
execv execv
execve execve
execvp execvp
system

View File

@@ -25,6 +25,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
@@ -34,6 +35,7 @@
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <signal.h>
#ifdef HAVE_STDBOOL_H #ifdef HAVE_STDBOOL_H
# include <stdbool.h> # include <stdbool.h>
#else #else
@@ -193,7 +195,8 @@ exec_wrapper(const char *cmnd, char * const argv[], char * const envp[],
static int static int
execl_wrapper(int type, const char *name, const char *arg, va_list ap) execl_wrapper(int type, const char *name, const char *arg, va_list ap)
{ {
char **argv, **envp = environ; char * const *envp = environ;
char **argv;
int argc = 1; int argc = 1;
va_list ap2; va_list ap2;
debug_decl(execl_wrapper, SUDO_DEBUG_EXEC); debug_decl(execl_wrapper, SUDO_DEBUG_EXEC);
@@ -219,6 +222,72 @@ execl_wrapper(int type, const char *name, const char *arg, va_list ap)
debug_return_int(-1); debug_return_int(-1);
} }
static int
system_wrapper(const char *cmnd)
{
char * const argv[] = { "sh", "-c", (char *)cmnd, NULL };
const char shell[] = _PATH_SUDO_BSHELL;
struct sigaction saveint, savequit, sa;
sigset_t mask, omask;
pid_t child;
int status;
debug_decl(system_wrapper, SUDO_DEBUG_EXEC);
/* Special case for NULL command, just check whether shell exists. */
if (cmnd == NULL)
debug_return_int(access(shell, X_OK) == 0);
/* First, block signals to avoid potential race conditions. */
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &mask, &omask) == -1)
debug_return_int(-1);
switch (child = vfork()) {
case -1:
/* error */
(void)sigprocmask(SIG_SETMASK, &omask, NULL);
debug_return_int(-1);
case 0:
/* child */
if (sigprocmask(SIG_SETMASK, &omask, NULL) != -1)
exec_wrapper(shell, argv, environ, false);
_exit(127);
default:
/* parent */
break;
}
/* We must ignore SIGINT and SIGQUIT until the command finishes. */
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
(void)sigaction(SIGINT, &sa, &saveint);
(void)sigaction(SIGQUIT, &sa, &savequit);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
(void)sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;) {
if (waitpid(child, &status, 0) == -1) {
if (errno == EINTR)
continue;
status = -1;
}
break;
}
/* Restore signal mask and handlers. */
(void)sigprocmask(SIG_SETMASK, &omask, NULL);
(void)sigaction(SIGINT, &saveint, NULL);
(void)sigaction(SIGQUIT, &savequit, NULL);
debug_return_int(status);
}
#ifdef HAVE___INTERPOSE #ifdef HAVE___INTERPOSE
/* /*
* Mac OS X 10.4 and above has support for library symbol interposition. * Mac OS X 10.4 and above has support for library symbol interposition.
@@ -229,6 +298,12 @@ typedef struct interpose_s {
void *orig_func; void *orig_func;
} interpose_t; } interpose_t;
static int
my_system(const char *cmnd)
{
return system_wrapper(cmnd);
}
static int static int
my_execve(const char *cmnd, char * const argv[], char * const envp[]) my_execve(const char *cmnd, char * const argv[], char * const envp[])
{ {
@@ -238,7 +313,7 @@ my_execve(const char *cmnd, char * const argv[], char * const envp[])
static int static int
my_execv(const char *cmnd, char * const argv[]) my_execv(const char *cmnd, char * const argv[])
{ {
return execve(cmnd, argv, environ); return exec_wrapper(cmnd, argv, environ, false);
} }
#ifdef HAVE_EXECVPE #ifdef HAVE_EXECVPE
@@ -294,6 +369,7 @@ my_execlp(const char *name, const char *arg, ...)
/* Magic to tell dyld to do symbol interposition. */ /* Magic to tell dyld to do symbol interposition. */
__attribute__((__used__)) static const interpose_t interposers[] __attribute__((__used__)) static const interpose_t interposers[]
__attribute__((__section__("__DATA,__interpose"))) = { __attribute__((__section__("__DATA,__interpose"))) = {
{ (void *)my_system, (void *)system },
{ (void *)my_execl, (void *)execl }, { (void *)my_execl, (void *)execl },
{ (void *)my_execle, (void *)execle }, { (void *)my_execle, (void *)execle },
{ (void *)my_execlp, (void *)execlp }, { (void *)my_execlp, (void *)execlp },
@@ -332,6 +408,12 @@ sudo_shl_get_next(const char *symbol, short type)
} }
# endif /* HAVE_SHL_LOAD */ # endif /* HAVE_SHL_LOAD */
sudo_dso_public int
system(const char *cmnd)
{
return system_wrapper(cmnd);
}
sudo_dso_public int sudo_dso_public int
execve(const char *cmnd, char * const argv[], char * const envp[]) execve(const char *cmnd, char * const argv[], char * const envp[])
{ {