[PATCH 18/19] mount.cifs: drop capabilities if libcap is available
Jeff Layton <[email protected]>
| Newsgroups | gmane.linux.file-systems.cifs |
|---|---|
| Message-ID | <[email protected]> |
From: Jeff Layton <[email protected]> Might as well be as safe as possible. Have child drop all capabilities, and have the parent drop all but CAP_SYS_ADMIN (needed for mounting) and CAP_DAC_OVERRIDE (needed in case mtab isn't writable by root). We might even eventually consider being clever and dropping CAP_DAC_OVERRIDE when root has access to the mtab. Signed-off-by: Jeff Layton <[email protected]> --- Makefile.am | 3 ++ aclocal/libcap.m4 | 20 +++++++++++++++ configure.ac | 3 ++ mount.cifs.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 0 deletions(-) create mode 100644 aclocal/libcap.m4 diff --git a/Makefile.am b/Makefile.am index fea8bdc..605206e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,10 @@ AM_CFLAGS = -Wall +ACLOCAL_AMFLAGS = -I aclocal + root_sbindir = "/sbin" root_sbin_PROGRAMS = mount.cifs mount_cifs_SOURCES = mount.cifs.c mtab.c util.c +mount_cifs_LDADD = @LIBCAP@ man_MANS = mount.cifs.8 diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4 new file mode 100644 index 0000000..0b42689 --- /dev/null +++ b/aclocal/libcap.m4 @@ -0,0 +1,20 @@ +dnl Checks for libcap.so +dnl +AC_DEFUN([AC_LIBCAP], [ + + dnl look for prctl + AC_CHECK_FUNC([prctl], , ) + + dnl look for the library; do not add to LIBS if found + AC_CHECK_LIB([cap], [cap_get_proc], enable_libcap="yes", enable_libcap="no", ) + + AC_CHECK_HEADERS([sys/capability.h], , + [AC_MSG_WARN([libcap headers not found. mount.cifs will be built without support for dropping capabilities. Consider installing libcap-devel.]) ; enable_libcap="no"]) + + if test "$enable_libcap" = "yes"; then + AC_DEFINE([HAVE_LIBCAP],[1], [Define if libcap exists]) + LIBCAP=-lcap + AC_SUBST(LIBCAP) + fi + +])dnl diff --git a/configure.ac b/configure.ac index 9f00bea..46a5848 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,7 @@ AC_INIT([cifs-utils], [4.1], [[email protected]], [cifs-utils], [http://samba.or AC_CONFIG_SRCDIR([replace.h]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) +AC_CONFIG_MACRO_DIR(aclocal) AM_INIT_AUTOMAKE @@ -80,4 +81,6 @@ fi AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) +AC_LIBCAP + AC_OUTPUT diff --git a/mount.cifs.c b/mount.cifs.c index e292e40..bcbeb88 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -43,6 +43,9 @@ #include <fstab.h> #include <sys/mman.h> #include <sys/wait.h> +#ifdef HAVE_LIBCAP +#include <sys/capability.h> +#endif /* HAVE_LIBCAP */ #include "mount.h" #include "util.h" @@ -1131,6 +1134,63 @@ add_mtab_exit: return rc; } +#ifdef HAVE_LIBCAP +static int +drop_capabilities(int parent) +{ + int rc = 0; + cap_t caps; + cap_value_t cap_list[2]; + + caps = cap_get_proc(); + if (caps == NULL) { + fprintf(stderr, "Unable to get current capability set: %s\n", + strerror(errno)); + return EX_SYSERR; + } + + if (cap_clear(caps) == -1) { + fprintf(stderr, "Unable to clear capability set: %s\n", + strerror(errno)); + rc = EX_SYSERR; + goto free_caps; + } + + /* parent needs to keep some capabilities */ + if (parent) { + cap_list[0] = CAP_SYS_ADMIN; + cap_list[1] = CAP_DAC_OVERRIDE; + if (cap_set_flag(caps, CAP_PERMITTED, 2, cap_list, CAP_SET) == -1) { + fprintf(stderr, "Unable to set permitted capabilities: %s\n", + strerror(errno)); + rc = EX_SYSERR; + goto free_caps; + } + if (cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_list, CAP_SET) == -1) { + fprintf(stderr, "Unable to set effective capabilities: %s\n", + strerror(errno)); + rc = EX_SYSERR; + goto free_caps; + } + } + + if (cap_set_proc(caps) != 0) { + fprintf(stderr, "Unable to set current process capabilities: %s\n", + strerror(errno)); + rc = EX_SYSERR; + } +free_caps: + cap_free(caps); + return rc; +} +#else /* HAVE_LIBCAP */ +static int +drop_capabilities(int parent) +{ + return 0; +} +#endif /* HAVE_LIBCAP */ + /* have the child drop root privileges */ static int drop_child_privs(void) @@ -1166,6 +1226,10 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info, { int rc; + rc = drop_capabilities(0); + if (rc) + goto assemble_exit; + rc = drop_child_privs(); if (rc) goto assemble_exit; @@ -1278,6 +1342,10 @@ int main(int argc, char **argv) if (check_setuid()) return EX_USAGE; + rc = drop_capabilities(1); + if (rc) + return EX_SYSERR; + if (geteuid()) { fprintf(stderr, "%s: not installed setuid root - \"user\" " "CIFS mounts not supported.", thisprogram); -- 1.6.6.1