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
[Linux USB Development]
[Linux Media Development]
[Video for Linux]
[Linux NILFS]
[Linux Audio Users]
[Photo]
[Yosemite Info]
[Yosemite Photos]
[POF Sucks]
[Linux Kernel]
[Linux SCSI]
[XFree86]