Patchwork [18/19] mount.cifs: drop capabilities if libcap is available

login
register
mail settings
Submitter Jeff Layton
Date March 26, 2010, 2:25 p.m.
Message ID <1269613542-6402-19-git-send-email-jlayton@samba.org>
Download mbox | patch
Permalink /patch/48650/
State New
Headers show

Comments

Jeff Layton - March 26, 2010, 2:25 p.m.
From: Jeff Layton <jlayton@redhat.com>

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 <jlayton@redhat.com>
---
 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

Patch

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], [jlayton@samba.org], [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);