[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.