Add support for loading the sudo_intercept.so DSO.

This commit is contained in:
Todd C. Miller
2021-08-09 15:50:25 -06:00
parent 786e5865cb
commit 6287e8ca7d
18 changed files with 333 additions and 60 deletions

26
INSTALL
View File

@@ -257,8 +257,8 @@ Compilation options:
policy and I/O logging plugins. If the --disable-shared policy and I/O logging plugins. If the --disable-shared
option is specified, this support is disabled and the default option is specified, this support is disabled and the default
sudoers policy and I/O plugins are embedded in the sudo sudoers policy and I/O plugins are embedded in the sudo
binary itself. This will also disable the noexec option binary itself. This will also disable the intercept and noexec
as it too relies on dynamic shared object support. options as they also rely on dynamic shared object support.
--disable-shared-libutil --disable-shared-libutil
Disable the use of the dynamic libsudo_util library. By Disable the use of the dynamic libsudo_util library. By
@@ -274,8 +274,8 @@ Compilation options:
dynamic shared object. When the --enable-static-sudoers dynamic shared object. When the --enable-static-sudoers
option is specified, the sudoers plugin is compiled directly option is specified, the sudoers plugin is compiled directly
into the sudo binary. Unlike --disable-shared, this does into the sudo binary. Unlike --disable-shared, this does
not prevent other plugins from being used and the noexec not prevent other plugins from being used and the intercept
option will continue to function. and noexec options will continue to function.
--enable-tmpfiles.d=DIR --enable-tmpfiles.d=DIR
Set the directory to be used when installing the sudo Set the directory to be used when installing the sudo
@@ -381,16 +381,30 @@ Optional features:
not work, which may be the case on some SysV-based OS's not work, which may be the case on some SysV-based OS's
using STREAMS. using STREAMS.
--enable-intercept[=PATH]
Enable support for the "intercept" functionality which allows
sudo to perform a policy check when a dynamically-linked
program run by sudo attempts to execute another program.
For example, this means that for a shell run through sudo,
the individual commands run by the shell are also subject
to rules in the sudoers file. Please see the "Preventing
Shell Escapes" section in the sudoers man page for details.
If specified, PATH should be a fully qualified path name,
e.g. /usr/local/libexec/sudo/sudo_noexec.so. If PATH is
"no", intercept support will not be compiled in. The default
is to compile intercept support if libtool supports building
shared objects on your system.
--with-noexec[=PATH] --with-noexec[=PATH]
Enable support for the "noexec" functionality which prevents Enable support for the "noexec" functionality which prevents
a dynamically-linked program being run by sudo from executing a dynamically-linked program being run by sudo from executing
another program (think shell escapes). Please see the another program (think shell escapes). Please see the
"PREVENTING SHELL ESCAPES" section in the sudoers man page "Preventing Shell Escapes" section in the sudoers man page
for details. If specified, PATH should be a fully qualified for details. If specified, PATH should be a fully qualified
path name, e.g. /usr/local/libexec/sudo/sudo_noexec.so. If PATH path name, e.g. /usr/local/libexec/sudo/sudo_noexec.so. If PATH
is "no", noexec support will not be compiled in. The default is "no", noexec support will not be compiled in. The default
is to compile noexec support if libtool supports building is to compile noexec support if libtool supports building
shared objects on your OS. shared objects on your system.
--with-selinux --with-selinux
Enable support for role based access control (RBAC) on Enable support for role based access control (RBAC) on

75
configure vendored
View File

@@ -808,14 +808,19 @@ LDAP
SELINUX_USAGE SELINUX_USAGE
BSDAUTH_USAGE BSDAUTH_USAGE
DONT_LEAK_PATH_INFO DONT_LEAK_PATH_INFO
NOEXEC_MODULE PRELOAD_MODULE
CHECK_NOEXEC CHECK_NOEXEC
CHECK_INTERCEPT
INSTALL_NOEXEC INSTALL_NOEXEC
INSTALL_INTERCEPT
INSTALL_BACKUP INSTALL_BACKUP
sesh_file sesh_file
noexec_file noexec_file
NOEXECDIR NOEXECDIR
NOEXECFILE NOEXECFILE
intercept_file
INTERCEPTDIR
INTERCEPTFILE
mansectform mansectform
mansectsu mansectsu
devdir devdir
@@ -1041,6 +1046,7 @@ with_gnu_ld
with_sysroot with_sysroot
enable_libtool_lock enable_libtool_lock
with_libtool with_libtool
enable_intercept
with_noexec with_noexec
with_netsvc with_netsvc
enable_sia enable_sia
@@ -1751,6 +1757,7 @@ Optional Features:
--enable-fast-install[=PKGS] --enable-fast-install[=PKGS]
optimize for fast installation [default=yes] optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds) --disable-libtool-lock avoid locking (might break parallel builds)
--enable-intercept fully qualified pathname of sudo_intercept.so
--disable-sia Disable SIA on Digital UNIX --disable-sia Disable SIA on Digital UNIX
--disable-largefile omit support for large files --disable-largefile omit support for large files
--disable-pam-session Disable PAM session support --disable-pam-session Disable PAM session support
@@ -3534,6 +3541,11 @@ ac_config_headers="$ac_config_headers config.h pathnames.h"
@@ -3580,6 +3592,7 @@ path_info=on
ldap_conf=/etc/ldap.conf ldap_conf=/etc/ldap.conf
ldap_secret=/etc/ldap.secret ldap_secret=/etc/ldap.secret
netsvc_conf=/etc/netsvc.conf netsvc_conf=/etc/netsvc.conf
intercept_file="$libexecdir/sudo/sudo_intercept.so"
noexec_file="$libexecdir/sudo/sudo_noexec.so" noexec_file="$libexecdir/sudo/sudo_noexec.so"
sesh_file="$libexecdir/sudo/sesh" sesh_file="$libexecdir/sudo/sesh"
nsswitch_conf=/etc/nsswitch.conf nsswitch_conf=/etc/nsswitch.conf
@@ -3593,9 +3606,11 @@ devsearch="/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev"
# End initial values for man page substitution # End initial values for man page substitution
# #
INSTALL_BACKUP= INSTALL_BACKUP=
INSTALL_INTERCEPT=
INSTALL_NOEXEC= INSTALL_NOEXEC=
CHECK_INTERCEPT=
CHECK_NOEXEC= CHECK_NOEXEC=
NOEXEC_MODULE=-module PRELOAD_MODULE=-module
exampledir='$(docdir)/examples' exampledir='$(docdir)/examples'
devdir='$(srcdir)' devdir='$(srcdir)'
PROGS="sudo" PROGS="sudo"
@@ -15534,6 +15549,7 @@ fi
if test "$enable_shared" = "no"; then if test "$enable_shared" = "no"; then
enable_intercept=no
with_noexec=no with_noexec=no
enable_dlopen=no enable_dlopen=no
lt_cv_dlopen=none lt_cv_dlopen=none
@@ -15544,6 +15560,23 @@ fi
LIBDL="$lt_cv_dlopen_libs" LIBDL="$lt_cv_dlopen_libs"
SHLIB_ENABLE="$enable_dlopen" SHLIB_ENABLE="$enable_dlopen"
# Check whether --enable-intercept was given.
if test ${enable_intercept+y}
then :
enableval=$enable_intercept; case "$enableval" in
yes) ;;
no) ;;
*) intercept_file="$enableval"
;;
esac
else $as_nop
enable_intercept="$intercept_file"
fi
INTERCEPTFILE="sudo_intercept.so"
INTERCEPTDIR="`echo $intercept_file|sed -e 's:^${\([^}]*\)}:$(\1):' -e 's:^\(.*\)/[^/]*:\1:'`"
# Check whether --with-noexec was given. # Check whether --with-noexec was given.
if test ${with_noexec+y} if test ${with_noexec+y}
@@ -16609,7 +16642,7 @@ done
# Build sudo_noexec.so as a shared library, not a module. # Build sudo_noexec.so as a shared library, not a module.
# On Darwin, modules and shared libraries are incompatible. # On Darwin, modules and shared libraries are incompatible.
NOEXEC_MODULE= PRELOAD_MODULE=
# Mach monotonic timer that runs while sleeping # Mach monotonic timer that runs while sleeping
ac_fn_c_check_func "$LINENO" "mach_continuous_time" "ac_cv_func_mach_continuous_time" ac_fn_c_check_func "$LINENO" "mach_continuous_time" "ac_cv_func_mach_continuous_time"
@@ -16787,7 +16820,13 @@ if test X"$enable_pvs_studio" = X"yes"; then
EOF EOF
fi fi
if test X"$with_noexec" != X"no"; then if test X"$enable_intercept" = X"no"; then
intercept_file=disabled
fi
if test X"$with_noexec" = X"no"; then
noexec_file=disabled
fi
if test X"${intercept_file} ${noexec_file}" != X"disabled disabled"; then
cat >>confdefs.h <<EOF cat >>confdefs.h <<EOF
#define RTLD_PRELOAD_VAR "$RTLD_PRELOAD_VAR" #define RTLD_PRELOAD_VAR "$RTLD_PRELOAD_VAR"
EOF EOF
@@ -16808,8 +16847,6 @@ EOF
EOF EOF
fi fi
else
noexec_file=disabled
fi fi
AUTH_REG=${AUTH_REG# } AUTH_REG=${AUTH_REG# }
@@ -29345,6 +29382,13 @@ if test "$exec_prefix" = '$(prefix)'; then
fi fi
fi fi
# Update exec_prefix in intercept_file
_intercept_file=
while test X"$intercept_file" != X"$_intercept_file"; do
_intercept_file="$intercept_file"
eval intercept_file="$_intercept_file"
done
# Update exec_prefix in noexec_file # Update exec_prefix in noexec_file
_noexec_file= _noexec_file=
while test X"$noexec_file" != X"$_noexec_file"; do while test X"$noexec_file" != X"$_noexec_file"; do
@@ -29367,6 +29411,25 @@ while test X"$plugindir" != X"$_plugindir"; do
done done
exec_prefix="$oexec_prefix" exec_prefix="$oexec_prefix"
if test X"$enable_intercept" != X"no"; then
PROGS="${PROGS} sudo_intercept.la"
INSTALL_INTERCEPT="install-intercept"
# Can't use sanitizers with LD_PRELOAD
if test "$enable_sanitizer" != "yes"; then
CHECK_INTERCEPT=check_intercept
fi
cat >>confdefs.h <<EOF
#define _PATH_SUDO_INTERCEPT "$intercept_file"
EOF
else
cat >>confdefs.h <<EOF
#define _PATH_SUDO_INTERCEPT NULL
EOF
fi
if test X"$with_noexec" != X"no"; then if test X"$with_noexec" != X"no"; then
PROGS="${PROGS} sudo_noexec.la" PROGS="${PROGS} sudo_noexec.la"
INSTALL_NOEXEC="install-noexec" INSTALL_NOEXEC="install-noexec"

View File

@@ -69,14 +69,19 @@ AC_SUBST([SEMAN])
AC_SUBST([devdir]) AC_SUBST([devdir])
AC_SUBST([mansectsu]) AC_SUBST([mansectsu])
AC_SUBST([mansectform]) AC_SUBST([mansectform])
AC_SUBST([INTERCEPTFILE])
AC_SUBST([INTERCEPTDIR])
AC_SUBST([intercept_file])
AC_SUBST([NOEXECFILE]) AC_SUBST([NOEXECFILE])
AC_SUBST([NOEXECDIR]) AC_SUBST([NOEXECDIR])
AC_SUBST([noexec_file]) AC_SUBST([noexec_file])
AC_SUBST([sesh_file]) AC_SUBST([sesh_file])
AC_SUBST([INSTALL_BACKUP]) AC_SUBST([INSTALL_BACKUP])
AC_SUBST([INSTALL_INTERCEPT])
AC_SUBST([INSTALL_NOEXEC]) AC_SUBST([INSTALL_NOEXEC])
AC_SUBST([CHECK_INTERCEPT])
AC_SUBST([CHECK_NOEXEC]) AC_SUBST([CHECK_NOEXEC])
AC_SUBST([NOEXEC_MODULE]) AC_SUBST([PRELOAD_MODULE])
AC_SUBST([DONT_LEAK_PATH_INFO]) AC_SUBST([DONT_LEAK_PATH_INFO])
AC_SUBST([BSDAUTH_USAGE]) AC_SUBST([BSDAUTH_USAGE])
AC_SUBST([SELINUX_USAGE]) AC_SUBST([SELINUX_USAGE])
@@ -209,6 +214,7 @@ path_info=on
ldap_conf=/etc/ldap.conf ldap_conf=/etc/ldap.conf
ldap_secret=/etc/ldap.secret ldap_secret=/etc/ldap.secret
netsvc_conf=/etc/netsvc.conf netsvc_conf=/etc/netsvc.conf
intercept_file="$libexecdir/sudo/sudo_intercept.so"
noexec_file="$libexecdir/sudo/sudo_noexec.so" noexec_file="$libexecdir/sudo/sudo_noexec.so"
sesh_file="$libexecdir/sudo/sesh" sesh_file="$libexecdir/sudo/sesh"
nsswitch_conf=/etc/nsswitch.conf nsswitch_conf=/etc/nsswitch.conf
@@ -226,9 +232,11 @@ dnl Initial values for Makefile variables listed above
dnl May be overridden by environment variables.. dnl May be overridden by environment variables..
dnl dnl
INSTALL_BACKUP= INSTALL_BACKUP=
INSTALL_INTERCEPT=
INSTALL_NOEXEC= INSTALL_NOEXEC=
CHECK_INTERCEPT=
CHECK_NOEXEC= CHECK_NOEXEC=
NOEXEC_MODULE=-module PRELOAD_MODULE=-module
exampledir='$(docdir)/examples' exampledir='$(docdir)/examples'
devdir='$(srcdir)' devdir='$(srcdir)'
PROGS="sudo" PROGS="sudo"
@@ -1657,9 +1665,10 @@ AC_ARG_WITH(libtool, [AS_HELP_STRING([--with-libtool=PATH], [specify path to lib
esac]) esac])
dnl dnl
dnl Defer with_noexec until after libtool magic runs dnl Defer enable_intercept and with_noexec until after libtool magic runs
dnl dnl
if test "$enable_shared" = "no"; then if test "$enable_shared" = "no"; then
enable_intercept=no
with_noexec=no with_noexec=no
enable_dlopen=no enable_dlopen=no
lt_cv_dlopen=none lt_cv_dlopen=none
@@ -1670,6 +1679,18 @@ fi
LIBDL="$lt_cv_dlopen_libs" LIBDL="$lt_cv_dlopen_libs"
SHLIB_ENABLE="$enable_dlopen" SHLIB_ENABLE="$enable_dlopen"
AC_ARG_ENABLE(intercept,
[AS_HELP_STRING([--enable-intercept], [fully qualified pathname of sudo_intercept.so])],
[ case "$enableval" in
yes) ;;
no) ;;
*) intercept_file="$enableval"
;;
esac
], [enable_intercept="$intercept_file"])
INTERCEPTFILE="sudo_intercept.so"
INTERCEPTDIR="`echo $intercept_file|sed -e 's:^${\([[^}]]*\)}:$(\1):' -e 's:^\(.*\)/[[^/]]*:\1:'`"
AC_ARG_WITH(noexec, [AS_HELP_STRING([--with-noexec[[=PATH]]], [fully qualified pathname of sudo_noexec.so])], AC_ARG_WITH(noexec, [AS_HELP_STRING([--with-noexec[[=PATH]]], [fully qualified pathname of sudo_noexec.so])],
[case $with_noexec in [case $with_noexec in
yes) ;; yes) ;;
@@ -2174,7 +2195,7 @@ case "$host" in
# Build sudo_noexec.so as a shared library, not a module. # Build sudo_noexec.so as a shared library, not a module.
# On Darwin, modules and shared libraries are incompatible. # On Darwin, modules and shared libraries are incompatible.
NOEXEC_MODULE= PRELOAD_MODULE=
# Mach monotonic timer that runs while sleeping # Mach monotonic timer that runs while sleeping
AC_CHECK_FUNCS([mach_continuous_time]) AC_CHECK_FUNCS([mach_continuous_time])
@@ -2261,7 +2282,13 @@ fi
dnl dnl
dnl Library preloading to support NOEXEC dnl Library preloading to support NOEXEC
dnl dnl
if test X"$with_noexec" != X"no"; then if test X"$enable_intercept" = X"no"; then
intercept_file=disabled
fi
if test X"$with_noexec" = X"no"; then
noexec_file=disabled
fi
if test X"${intercept_file} ${noexec_file}" != X"disabled disabled"; then
SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_VAR, "$RTLD_PRELOAD_VAR") SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_VAR, "$RTLD_PRELOAD_VAR")
SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DELIM, "$RTLD_PRELOAD_DELIM") SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DELIM, "$RTLD_PRELOAD_DELIM")
if test -n "$RTLD_PRELOAD_DEFAULT"; then if test -n "$RTLD_PRELOAD_DEFAULT"; then
@@ -2270,8 +2297,6 @@ if test X"$with_noexec" != X"no"; then
if test -n "$RTLD_PRELOAD_ENABLE_VAR"; then if test -n "$RTLD_PRELOAD_ENABLE_VAR"; then
SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_ENABLE_VAR, "$RTLD_PRELOAD_ENABLE_VAR") SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_ENABLE_VAR, "$RTLD_PRELOAD_ENABLE_VAR")
fi fi
else
noexec_file=disabled
fi fi
dnl dnl
@@ -4726,6 +4751,13 @@ if test "$exec_prefix" = '$(prefix)'; then
fi fi
fi fi
# Update exec_prefix in intercept_file
_intercept_file=
while test X"$intercept_file" != X"$_intercept_file"; do
_intercept_file="$intercept_file"
eval intercept_file="$_intercept_file"
done
# Update exec_prefix in noexec_file # Update exec_prefix in noexec_file
_noexec_file= _noexec_file=
while test X"$noexec_file" != X"$_noexec_file"; do while test X"$noexec_file" != X"$_noexec_file"; do
@@ -4751,6 +4783,19 @@ exec_prefix="$oexec_prefix"
dnl dnl
dnl Defer setting _PATH_SUDO_NOEXEC, etc until after exec_prefix is set dnl Defer setting _PATH_SUDO_NOEXEC, etc until after exec_prefix is set
dnl dnl
if test X"$enable_intercept" != X"no"; then
PROGS="${PROGS} sudo_intercept.la"
INSTALL_INTERCEPT="install-intercept"
# Can't use sanitizers with LD_PRELOAD
if test "$enable_sanitizer" != "yes"; then
CHECK_INTERCEPT=check_intercept
fi
SUDO_DEFINE_UNQUOTED(_PATH_SUDO_INTERCEPT, "$intercept_file", [The fully qualified pathname of sudo_intercept.so])
else
SUDO_DEFINE_UNQUOTED(_PATH_SUDO_INTERCEPT, NULL)
fi
if test X"$with_noexec" != X"no"; then if test X"$with_noexec" != X"no"; then
PROGS="${PROGS} sudo_noexec.la" PROGS="${PROGS} sudo_noexec.la"
INSTALL_NOEXEC="install-noexec" INSTALL_NOEXEC="install-noexec"

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@" "March 2, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDO.CONF" "@mansectform@" "June 22, 2021" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -229,6 +229,7 @@ For example:
.nf .nf
.sp .sp
.RS 6n .RS 6n
Path intercept @intercept_file@
Path noexec @noexec_file@ Path noexec @noexec_file@
Path askpass /usr/X11R6/bin/ssh-askpass Path askpass /usr/X11R6/bin/ssh-askpass
.RE .RE
@@ -286,6 +287,36 @@ functions, for example
BSD, BSD,
macOS and Solaris. macOS and Solaris.
.TP 10n .TP 10n
intercept
.br
The fully-qualified path to a shared library containing wrappers
for the
\fBexecl\fR(),
\fBexecle\fR(),
\fBexeclp\fR(),
\fBexect\fR(),
\fBexecv\fR(),
\fBexecve\fR(),
\fBexecvP\fR(),
\fBexecvp\fR(),
\fBexecvpe\fR(),
\fBfexecve\fR(),
\fBpopen\fR(),
\fBposix_spawn\fR(),
\fBposix_spawnp\fR(),
\fBsystem\fR(),
and
\fBwordexp\fR()
library functions that intercept attempts to run further commands and
perform a policy check before allowing them to be executed.
This is used to implement the
\fIintercept\fR
functionality on systems that support
\fRLD_PRELOAD\fR
or its equivalent.
The default value is
\fI@intercept_file@\fR.
.TP 10n
noexec noexec
The fully-qualified path to a shared library containing wrappers The fully-qualified path to a shared library containing wrappers
for the for the
@@ -738,6 +769,21 @@ front end configuration
# #
#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev #Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo command interception:
# Path intercept /path/to/sudo_intercept.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that perform a policy check
# to verify the command is allowed and simply return an error if not.
# This is used to implement the "intercept" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_intercept.so file.
#
#Path intercept @plugindir@/sudo_intercept.so
# #
# Sudo noexec: # Sudo noexec:
# Path noexec /path/to/sudo_noexec.so # Path noexec /path/to/sudo_noexec.so

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 March 2, 2021 .Dd June 22, 2021
.Dt SUDO.CONF @mansectform@ .Dt SUDO.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -209,6 +209,7 @@ line consists of the
keyword, followed by the name of the path to set and its value. keyword, followed by the name of the path to set and its value.
For example: For example:
.Bd -literal -offset indent .Bd -literal -offset indent
Path intercept @intercept_file@
Path noexec @noexec_file@ Path noexec @noexec_file@
Path askpass /usr/X11R6/bin/ssh-askpass Path askpass /usr/X11R6/bin/ssh-askpass
.Ed .Ed
@@ -262,6 +263,34 @@ or
functions, for example functions, for example
.Bx , .Bx ,
macOS and Solaris. macOS and Solaris.
.It intercept
The fully-qualified path to a shared library containing wrappers
for the
.Fn execl ,
.Fn execle ,
.Fn execlp ,
.Fn exect ,
.Fn execv ,
.Fn execve ,
.Fn execvP ,
.Fn execvp ,
.Fn execvpe ,
.Fn fexecve ,
.Fn popen ,
.Fn posix_spawn ,
.Fn posix_spawnp ,
.Fn system ,
and
.Fn wordexp
library functions that intercept attempts to run further commands and
perform a policy check before allowing them to be executed.
This is used to implement the
.Em intercept
functionality on systems that support
.Ev LD_PRELOAD
or its equivalent.
The default value is
.Pa @intercept_file@ .
.It noexec .It noexec
The fully-qualified path to a shared library containing wrappers The fully-qualified path to a shared library containing wrappers
for the for the
@@ -672,6 +701,21 @@ front end configuration
# #
#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev #Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo command interception:
# Path intercept /path/to/sudo_intercept.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that perform a policy check
# to verify the command is allowed and simply return an error if not.
# This is used to implement the "intercept" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_intercept.so file.
#
#Path intercept @plugindir@/sudo_intercept.so
# #
# Sudo noexec: # Sudo noexec:
# Path noexec /path/to/sudo_noexec.so # Path noexec /path/to/sudo_noexec.so

View File

@@ -38,6 +38,21 @@
# #
#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev #Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo command interception:
# Path intercept /path/to/sudo_intercept.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that perform a policy check
# to verify the command is allowed and simply return an error if not.
# This is used to implement the "intercept" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_intercept.so file.
#
#Path intercept @plugindir@/sudo_intercept.so
# #
# Sudo noexec: # Sudo noexec:
# Path noexec /path/to/sudo_noexec.so # Path noexec /path/to/sudo_noexec.so

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2011-2014 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2011-2017, 2019-2021 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
@@ -65,6 +65,7 @@ sudo_dso_public int sudo_conf_read_v1(const char *conf_file, int conf_types);
/* Accessor functions. */ /* Accessor functions. */
sudo_dso_public const char *sudo_conf_askpass_path_v1(void); sudo_dso_public const char *sudo_conf_askpass_path_v1(void);
sudo_dso_public const char *sudo_conf_sesh_path_v1(void); sudo_dso_public const char *sudo_conf_sesh_path_v1(void);
sudo_dso_public const char *sudo_conf_intercept_path_v1(void);
sudo_dso_public const char *sudo_conf_noexec_path_v1(void); sudo_dso_public const char *sudo_conf_noexec_path_v1(void);
sudo_dso_public const char *sudo_conf_plugin_dir_path_v1(void); sudo_dso_public const char *sudo_conf_plugin_dir_path_v1(void);
sudo_dso_public const char *sudo_conf_devsearch_path_v1(void); sudo_dso_public const char *sudo_conf_devsearch_path_v1(void);
@@ -79,6 +80,7 @@ sudo_dso_public int sudo_conf_max_groups_v1(void);
sudo_dso_public void sudo_conf_clear_paths_v1(void); sudo_dso_public void sudo_conf_clear_paths_v1(void);
#define sudo_conf_askpass_path() sudo_conf_askpass_path_v1() #define sudo_conf_askpass_path() sudo_conf_askpass_path_v1()
#define sudo_conf_sesh_path() sudo_conf_sesh_path_v1() #define sudo_conf_sesh_path() sudo_conf_sesh_path_v1()
#define sudo_conf_intercept_path() sudo_conf_intercept_path_v1()
#define sudo_conf_noexec_path() sudo_conf_noexec_path_v1() #define sudo_conf_noexec_path() sudo_conf_noexec_path_v1()
#define sudo_conf_plugin_dir_path() sudo_conf_plugin_dir_path_v1() #define sudo_conf_plugin_dir_path() sudo_conf_plugin_dir_path_v1()
#define sudo_conf_devsearch_path() sudo_conf_devsearch_path_v1() #define sudo_conf_devsearch_path() sudo_conf_devsearch_path_v1()

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2017 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2021 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
@@ -104,13 +104,15 @@ static struct sudo_conf_table sudo_conf_var_table[] = {
/* Indexes into path_table[] below (order is important). */ /* Indexes into path_table[] below (order is important). */
#define SUDO_CONF_PATH_ASKPASS 0 #define SUDO_CONF_PATH_ASKPASS 0
#define SUDO_CONF_PATH_SESH 1 #define SUDO_CONF_PATH_SESH 1
#define SUDO_CONF_PATH_NOEXEC 2 #define SUDO_CONF_PATH_INTERCEPT 2
#define SUDO_CONF_PATH_PLUGIN_DIR 3 #define SUDO_CONF_PATH_NOEXEC 3
#define SUDO_CONF_PATH_DEVSEARCH 4 #define SUDO_CONF_PATH_PLUGIN_DIR 4
#define SUDO_CONF_PATH_DEVSEARCH 5
#define SUDO_CONF_PATH_INITIALIZER { \ #define SUDO_CONF_PATH_INITIALIZER { \
{ "askpass", sizeof("askpass") - 1, false, _PATH_SUDO_ASKPASS }, \ { "askpass", sizeof("askpass") - 1, false, _PATH_SUDO_ASKPASS }, \
{ "sesh", sizeof("sesh") - 1, false, _PATH_SUDO_SESH }, \ { "sesh", sizeof("sesh") - 1, false, _PATH_SUDO_SESH }, \
{ "intercept", sizeof("intercept") - 1, false, _PATH_SUDO_INTERCEPT }, \
{ "noexec", sizeof("noexec") - 1, false, _PATH_SUDO_NOEXEC }, \ { "noexec", sizeof("noexec") - 1, false, _PATH_SUDO_NOEXEC }, \
{ "plugin_dir", sizeof("plugin_dir") - 1, false, _PATH_SUDO_PLUGIN_DIR }, \ { "plugin_dir", sizeof("plugin_dir") - 1, false, _PATH_SUDO_PLUGIN_DIR }, \
{ "devsearch", sizeof("devsearch") - 1, false, _PATH_SUDO_DEVSEARCH }, \ { "devsearch", sizeof("devsearch") - 1, false, _PATH_SUDO_DEVSEARCH }, \
@@ -141,7 +143,7 @@ static struct sudo_conf_data {
struct sudo_conf_settings settings; struct sudo_conf_settings settings;
struct sudo_conf_debug_list debugging; struct sudo_conf_debug_list debugging;
struct plugin_info_list plugins; struct plugin_info_list plugins;
struct sudo_conf_path_table path_table[6]; struct sudo_conf_path_table path_table[7];
} sudo_conf_data = { } sudo_conf_data = {
SUDO_CONF_SETTINGS_INITIALIZER, SUDO_CONF_SETTINGS_INITIALIZER,
TAILQ_HEAD_INITIALIZER(sudo_conf_data.debugging), TAILQ_HEAD_INITIALIZER(sudo_conf_data.debugging),
@@ -480,6 +482,12 @@ sudo_conf_sesh_path_v1(void)
return sudo_conf_data.path_table[SUDO_CONF_PATH_SESH].pval; return sudo_conf_data.path_table[SUDO_CONF_PATH_SESH].pval;
} }
const char *
sudo_conf_intercept_path_v1(void)
{
return sudo_conf_data.path_table[SUDO_CONF_PATH_INTERCEPT].pval;
}
const char * const char *
sudo_conf_noexec_path_v1(void) sudo_conf_noexec_path_v1(void)
{ {

View File

@@ -9,6 +9,7 @@ sudo_conf_developer_mode_v1
sudo_conf_devsearch_path_v1 sudo_conf_devsearch_path_v1
sudo_conf_disable_coredump_v1 sudo_conf_disable_coredump_v1
sudo_conf_group_source_v1 sudo_conf_group_source_v1
sudo_conf_intercept_path_v1
sudo_conf_max_groups_v1 sudo_conf_max_groups_v1
sudo_conf_noexec_path_v1 sudo_conf_noexec_path_v1
sudo_conf_plugin_dir_path_v1 sudo_conf_plugin_dir_path_v1

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 1996, 1998, 1999, 2001, 2004, 2005, 2007-2014 * Copyright (c) 1996, 1998, 1999, 2001, 2004, 2005, 2007-2021
* Todd C. Miller <Todd.Miller@sudo.ws>. * 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
@@ -162,6 +162,10 @@
# undef _PATH_SUDO_SENDMAIL # undef _PATH_SUDO_SENDMAIL
#endif /* _PATH_SUDO_SENDMAIL */ #endif /* _PATH_SUDO_SENDMAIL */
#ifndef _PATH_SUDO_INTERCEPT
# undef _PATH_SUDO_INTERCEPT
#endif /* _PATH_SUDO_INTERCEPT */
#ifndef _PATH_SUDO_NOEXEC #ifndef _PATH_SUDO_NOEXEC
# undef _PATH_SUDO_NOEXEC # undef _PATH_SUDO_NOEXEC
#endif /* _PATH_SUDO_NOEXEC */ #endif /* _PATH_SUDO_NOEXEC */

View File

@@ -1,7 +1,7 @@
# #
# SPDX-License-Identifier: ISC # SPDX-License-Identifier: ISC
# #
# Copyright (c) 2010-2021 # Copyright (c) 2010-2021 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
@@ -64,8 +64,9 @@ LT_LDFLAGS = @LT_LDFLAGS@
# Flags to pass to libtool # Flags to pass to libtool
LTFLAGS = --tag=disable-static LTFLAGS = --tag=disable-static
# Build sudo_noexec as a module instead of a shared lib (except on macOS) # Flag to build sudo_module.so and sudo_noexec.so as modules instead of
NOEXEC_MODULE = @NOEXEC_MODULE@ # shared libs (except on macOS)
PRELOAD_MODULE = @PRELOAD_MODULE@
# Address sanitizer flags # Address sanitizer flags
ASAN_CFLAGS = @ASAN_CFLAGS@ ASAN_CFLAGS = @ASAN_CFLAGS@
@@ -179,7 +180,7 @@ sudo: $(OBJS) $(LT_LIBS) @STATIC_SUDOERS@
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(OBJS) $(SUDO_LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @STATIC_SUDOERS@ $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(OBJS) $(SUDO_LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @STATIC_SUDOERS@
sudo_noexec.la: sudo_noexec.lo sudo_noexec.la: sudo_noexec.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) $(LT_LDFLAGS) $(SSP_LDFLAGS) @LIBDL@ -o $@ sudo_noexec.lo $(NOEXEC_MODULE) -avoid-version -rpath $(noexecdir) -shrext .so $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) $(LT_LDFLAGS) $(SSP_LDFLAGS) @LIBDL@ -o $@ sudo_noexec.lo $(PRELOAD_MODULE) -avoid-version -rpath $(noexecdir) -shrext .so
sesh: $(SESH_OBJS) $(LT_LIBS) sesh: $(SESH_OBJS) $(LT_LIBS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SESH_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SESH_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
@@ -243,7 +244,8 @@ install-plugin:
install-fuzzer: install-fuzzer:
uninstall: uninstall:
-$(LIBTOOL) $(LTFLAGS) --mode=uninstall rm -f $(DESTDIR)$(noexecdir)/sudo_noexec.la -$(LIBTOOL) $(LTFLAGS) --mode=uninstall \
rm -f $(DESTDIR)$(noexecdir)/sudo_noexec.la
-rm -f $(DESTDIR)$(bindir)/sudo \ -rm -f $(DESTDIR)$(bindir)/sudo \
$(DESTDIR)$(bindir)/sudoedit \ $(DESTDIR)$(bindir)/sudoedit \
$(DESTDIR)$(libexecdir)/sudo/sesh \ $(DESTDIR)$(libexecdir)/sudo/sesh \

View File

@@ -248,7 +248,7 @@ exec_cmnd(struct command_details *details, int errfd)
#endif #endif
{ {
sudo_execve(details->execfd, details->command, details->argv, sudo_execve(details->execfd, details->command, details->argv,
details->envp, ISSET(details->flags, CD_NOEXEC)); details->envp, details->flags);
} }
} }
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s", sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s",
@@ -317,7 +317,7 @@ sudo_needs_pty(struct command_details *details)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
if (ISSET(details->flags, CD_USE_PTY)) if (ISSET(details->flags, CD_USE_PTY|CD_INTERCEPT|CD_LOG_CHILDREN))
return true; return true;
TAILQ_FOREACH(plugin, &io_plugins, entries) { TAILQ_FOREACH(plugin, &io_plugins, entries) {

View File

@@ -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-2021 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
@@ -173,20 +173,39 @@ disable_execute(char *envp[], const char *dso)
debug_return_ptr(envp); debug_return_ptr(envp);
} }
/*
* Trap execution of child processes in the command we are about to run.
* Uses LD_PRELOAD and the like to perform a policy check on child commands.
*/
char **
enable_intercept(char *envp[], const char *dso)
{
debug_decl(enable_intercept, SUDO_DEBUG_UTIL);
#ifdef RTLD_PRELOAD_VAR
if (dso != NULL)
envp = preload_dso(envp, dso);
#endif /* RTLD_PRELOAD_VAR */
debug_return_ptr(envp);
}
/* /*
* Like execve(2) but falls back to running through /bin/sh * Like execve(2) but falls back to running through /bin/sh
* ala execvp(3) if we get ENOEXEC. * ala execvp(3) if we get ENOEXEC.
*/ */
int int
sudo_execve(int fd, const char *path, char *const argv[], char *envp[], bool noexec) sudo_execve(int fd, const char *path, char *const argv[], char *envp[], int flags)
{ {
debug_decl(sudo_execve, SUDO_DEBUG_UTIL); debug_decl(sudo_execve, SUDO_DEBUG_UTIL);
sudo_debug_execve(SUDO_DEBUG_INFO, path, argv, envp); sudo_debug_execve(SUDO_DEBUG_INFO, path, argv, envp);
/* Modify the environment as needed to disable further execve(). */ /* Modify the environment as needed to trap execve(). */
if (noexec) if (ISSET(flags, CD_NOEXEC))
envp = disable_execute(envp, sudo_conf_noexec_path()); envp = disable_execute(envp, sudo_conf_noexec_path());
else if (ISSET(flags, CD_INTERCEPT|CD_LOG_CHILDREN))
envp = enable_intercept(envp, sudo_conf_intercept_path());
#ifdef HAVE_FEXECVE #ifdef HAVE_FEXECVE
if (fd != -1) if (fd != -1)

View File

@@ -502,7 +502,7 @@ selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
memcpy(&nargv[nargc], &argv[1], argc * sizeof(char *)); /* copies NULL */ memcpy(&nargv[nargc], &argv[1], argc * sizeof(char *)); /* copies NULL */
/* sesh will handle noexec for us. */ /* sesh will handle noexec for us. */
sudo_execve(-1, sesh, nargv, envp, false); sudo_execve(-1, sesh, nargv, envp, 0);
serrno = errno; serrno = errno;
free(nargv); free(nargv);
errno = serrno; errno = serrno;

View File

@@ -80,16 +80,19 @@ main(int argc, char *argv[], char *envp[])
if (strcmp(argv[1], "-e") == 0) { if (strcmp(argv[1], "-e") == 0) {
ret = sesh_sudoedit(argc, argv); ret = sesh_sudoedit(argc, argv);
} else { } else {
bool login_shell, noexec = false; bool login_shell;
char *cp, *cmnd; char *cp, *cmnd;
int flags = 0;
int fd = -1; int fd = -1;
/* If the first char of argv[0] is '-', we are running a login shell. */ /* If the first char of argv[0] is '-', we are running a login shell. */
login_shell = argv[0][0] == '-'; login_shell = argv[0][0] == '-';
/* If argv[0] ends in -noexec, pass the flag to sudo_execve() */ /* If argv[0] ends in -noexec, pass the flag to sudo_execve() */
if ((cp = strrchr(argv[0], '-')) != NULL && cp != argv[0]) if ((cp = strrchr(argv[0], '-')) != NULL && cp != argv[0]) {
noexec = strcmp(cp, "-noexec") == 0; if (strcmp(cp, "-noexec") == 0)
SET(flags, CD_NOEXEC);
}
/* 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=", 9) == 0) {
@@ -116,7 +119,7 @@ main(int argc, char *argv[], char *envp[])
*cp = '-'; *cp = '-';
argv[0] = cp; argv[0] = cp;
} }
sudo_execve(fd, cmnd, argv, envp, noexec); sudo_execve(fd, cmnd, argv, envp, flags);
sudo_warn(U_("unable to execute %s"), cmnd); sudo_warn(U_("unable to execute %s"), cmnd);
ret = SESH_ERR_FAILURE; ret = SESH_ERR_FAILURE;
} }

View File

@@ -724,8 +724,12 @@ command_info_to_details(char * const info[], struct command_details *details)
break; break;
} }
break; break;
case 'i':
SET_FLAG("intercept=", CD_INTERCEPT)
break;
case 'l': case 'l':
SET_STRING("login_class=", login_class) SET_STRING("login_class=", login_class)
SET_FLAG("log_children=", CD_LOG_CHILDREN)
break; break;
case 'n': case 'n':
if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {

View File

@@ -123,21 +123,23 @@ struct user_details {
#define CD_SET_GID 0x000004 #define CD_SET_GID 0x000004
#define CD_SET_EGID 0x000008 #define CD_SET_EGID 0x000008
#define CD_PRESERVE_GROUPS 0x000010 #define CD_PRESERVE_GROUPS 0x000010
#define CD_NOEXEC 0x000020 #define CD_INTERCEPT 0x000020
#define CD_SET_PRIORITY 0x000040 #define CD_NOEXEC 0x000040
#define CD_SET_UMASK 0x000080 #define CD_SET_PRIORITY 0x000080
#define CD_SET_TIMEOUT 0x000100 #define CD_SET_UMASK 0x000100
#define CD_SUDOEDIT 0x000200 #define CD_SET_TIMEOUT 0x000200
#define CD_BACKGROUND 0x000400 #define CD_SUDOEDIT 0x000400
#define CD_RBAC_ENABLED 0x000800 #define CD_BACKGROUND 0x000800
#define CD_USE_PTY 0x001000 #define CD_RBAC_ENABLED 0x001000
#define CD_SET_UTMP 0x002000 #define CD_USE_PTY 0x002000
#define CD_EXEC_BG 0x004000 #define CD_SET_UTMP 0x004000
#define CD_SUDOEDIT_FOLLOW 0x008000 #define CD_EXEC_BG 0x008000
#define CD_SUDOEDIT_CHECKDIR 0x010000 #define CD_SUDOEDIT_FOLLOW 0x010000
#define CD_SET_GROUPS 0x020000 #define CD_SUDOEDIT_CHECKDIR 0x020000
#define CD_LOGIN_SHELL 0x040000 #define CD_SET_GROUPS 0x040000
#define CD_OVERRIDE_UMASK 0x080000 #define CD_LOGIN_SHELL 0x080000
#define CD_OVERRIDE_UMASK 0x100000
#define CD_LOG_CHILDREN 0x200000
struct preserved_fd { struct preserved_fd {
TAILQ_ENTRY(preserved_fd) entries; TAILQ_ENTRY(preserved_fd) entries;

View File

@@ -92,8 +92,9 @@ void terminate_command(pid_t pid, bool use_pgrp);
bool sudo_terminated(struct command_status *cstat); bool sudo_terminated(struct command_status *cstat);
/* exec_common.c */ /* exec_common.c */
int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], bool noexec); int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], int flags);
char **disable_execute(char *envp[], const char *dso); char **disable_execute(char *envp[], const char *dso);
char **enable_monitor(char *envp[], const char *dso);
/* exec_nopty.c */ /* exec_nopty.c */
void exec_nopty(struct command_details *details, struct command_status *cstat); void exec_nopty(struct command_details *details, struct command_status *cstat);