On May 17, 2012, at 1:54 PM, Jeff Layton wrote: > statd drops all capabilities except for CAP_NET_BIND when it starts. It's > possible though that if it ever had a compromise that an attacker would be > able to invoke a setuid process (or something with file capabilities) in > order to reinstate some caps. > > This could happen as a result of the daemon becoming compromised, or > possibly as a result of the ha-callout program becoming compromised. Generally, I wonder what our exposure to this attack for a statd built without capability support. Just musing out loud. > In order to prevent that, have statd also prune the capability bounding > set to nothing prior to dropping capabilities. That ensures that the > process won't be able to reacquire capabilities via any means -- > including exec'ing a setuid program. > > We do however need to be cognizant of the fact that PR_CAPBSET_DROP was > only added in 2.6.25, so check to make sure that #define exists via > autoconf before we rely on it. In order to do that, we must add > ax_check_define.m4 from the GNU autoconf macro archive. On pre-2.6.25 kernels, the bounding set is a fixed system-wide setting. What we decided is to forego a run-time check here in favor of a build-time check. Would it be difficult to do both? > Cc: Chuck Lever <chuck.lever@xxxxxxxxxx> > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > --- > aclocal/ax_check_define.m4 | 92 ++++++++++++++++++++++++++++++++++++++++++++ > aclocal/libcap.m4 | 5 ++ > support/nsm/file.c | 23 +++++++++++ > 3 files changed, 120 insertions(+), 0 deletions(-) > create mode 100644 aclocal/ax_check_define.m4 > > diff --git a/aclocal/ax_check_define.m4 b/aclocal/ax_check_define.m4 > new file mode 100644 > index 0000000..4bc6948 > --- /dev/null > +++ b/aclocal/ax_check_define.m4 > @@ -0,0 +1,92 @@ > +# =========================================================================== > +# http://www.gnu.org/software/autoconf-archive/ax_check_define.html > +# =========================================================================== > +# > +# SYNOPSIS > +# > +# AC_CHECK_DEFINE([symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) > +# AX_CHECK_DEFINE([includes],[symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) > +# > +# DESCRIPTION > +# > +# Complements AC_CHECK_FUNC but it does not check for a function but for a > +# define to exist. Consider a usage like: > +# > +# AC_CHECK_DEFINE(__STRICT_ANSI__, CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500") > +# > +# LICENSE > +# > +# Copyright (c) 2008 Guido U. Draheim <guidod@xxxxxx> > +# > +# This program is free software; you can redistribute it and/or modify it > +# under the terms of the GNU General Public License as published by the > +# Free Software Foundation; either version 3 of the License, or (at your > +# option) any later version. > +# > +# This program is distributed in the hope that it will be useful, but > +# WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General > +# Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program. If not, see <http://www.gnu.org/licenses/>. > +# > +# As a special exception, the respective Autoconf Macro's copyright owner > +# gives unlimited permission to copy, distribute and modify the configure > +# scripts that are the output of Autoconf when processing the Macro. You > +# need not follow the terms of the GNU General Public License when using > +# or distributing such scripts, even though portions of the text of the > +# Macro appear in them. The GNU General Public License (GPL) does govern > +# all other use of the material that constitutes the Autoconf Macro. > +# > +# This special exception to the GPL applies to versions of the Autoconf > +# Macro released by the Autoconf Archive. When you make and distribute a > +# modified version of the Autoconf Macro, you may extend this special > +# exception to the GPL to apply to your modified version as well. > + > +#serial 8 > + > +AU_ALIAS([AC_CHECK_DEFINED], [AC_CHECK_DEFINE]) > +AC_DEFUN([AC_CHECK_DEFINE],[ > +AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl > +AC_CACHE_CHECK([for $1 defined], ac_var, > +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ > + #ifdef $1 > + int ok; > + #else > + choke me > + #endif > +]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) > +AS_IF([test AS_VAR_GET(ac_var) != "no"], [$2], [$3])dnl > +AS_VAR_POPDEF([ac_var])dnl > +]) > + > +AU_ALIAS([AX_CHECK_DEFINED], [AX_CHECK_DEFINE]) > +AC_DEFUN([AX_CHECK_DEFINE],[ > +AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$2_$1])dnl > +AC_CACHE_CHECK([for $2 defined in $1], ac_var, > +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <$1>]], [[ > + #ifdef $2 > + int ok; > + #else > + choke me > + #endif > +]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) > +AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl > +AS_VAR_POPDEF([ac_var])dnl > +]) > + > +AC_DEFUN([AX_CHECK_FUNC], > +[AS_VAR_PUSHDEF([ac_var], [ac_cv_func_$2])dnl > +AC_CACHE_CHECK([for $2], ac_var, > +dnl AC_LANG_FUNC_LINK_TRY > +[AC_LINK_IFELSE([AC_LANG_PROGRAM([$1 > + #undef $2 > + char $2 ();],[ > + char (*f) () = $2; > + return f != $2; ])], > + [AS_VAR_SET(ac_var, yes)], > + [AS_VAR_SET(ac_var, no)])]) > +AS_IF([test AS_VAR_GET(ac_var) = yes], [$3], [$4])dnl > +AS_VAR_POPDEF([ac_var])dnl > +])# AC_CHECK_FUNC > diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4 > index f8a0ed1..a310366 100644 > --- a/aclocal/libcap.m4 > +++ b/aclocal/libcap.m4 > @@ -5,6 +5,11 @@ AC_DEFUN([AC_LIBCAP], [ > dnl look for prctl > AC_CHECK_FUNC([prctl], , AC_MSG_ERROR([prctl syscall is not available])) > > + dnl check to see if PR_CAPBSET_DROP is defined > + AX_CHECK_DEFINE([linux/prctl.h], [PR_CAPBSET_DROP], > + AC_DEFINE([HAVE_PR_CAPBSET_DROP], 1, [Define to 1 if you have the 'PR_CAPBSET_DROP' capability defined.]), > + AC_MSG_WARN([PR_CAPBSET_DROP not defined! Unable to build in support for dropping the capabilities bounding set])) > + > AC_ARG_ENABLE([caps], > [AS_HELP_STRING([--disable-caps], [Disable capabilities support])]) > > diff --git a/support/nsm/file.c b/support/nsm/file.c > index 5dd52c1..8d946c0 100644 > --- a/support/nsm/file.c > +++ b/support/nsm/file.c > @@ -361,6 +361,26 @@ nsm_clear_capabilities(void) > return true; > } > > +static bool > +prune_bounding_set(void) > +{ > +#ifdef HAVE_PR_CAPBSET_DROP Can't you just do "#ifdef PR_CAPBSET_DROP" ? That obviates the need for the new aclocal script. > + int ret; > + unsigned long i; > + > + /* prune the bounding set to nothing */ > + for (i = 0; i <= CAP_LAST_CAP; ++i) { > + ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); > + if (ret) { > + xlog(L_ERROR, "Unable to prune capability %lu from " > + "bounding set: %m", i); > + return false; On modern kernels, there is the ability to disable capabilities bound to files. What if a caps-enabled statd is running on such a kernel? > + } > + } > +#endif /* HAVE_PR_CAPBSET_DROP */ > + return true; > +} > + > /** > * nsm_drop_privileges - drop root privileges > * @pidfd: file descriptor of a pid file > @@ -393,6 +413,9 @@ nsm_drop_privileges(const int pidfd) > return false; > } > > + if (!prune_bounding_set()) > + return false; > + > if (st.st_uid == 0) { > xlog_warn("Running as root. " > "chown %s to choose different user", nsm_base_dirname); > -- > 1.7.7.6 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Chuck Lever chuck[dot]lever[at]oracle[dot]com -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html