From patchwork Fri Mar 26 14:25:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 48650 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.samba.org (fn.samba.org [216.83.154.106]) by ozlabs.org (Postfix) with ESMTP id 5B73DB7C09 for ; Sat, 27 Mar 2010 01:26:30 +1100 (EST) Received: from fn.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id C809E46664; Fri, 26 Mar 2010 08:26:29 -0600 (MDT) X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on fn.samba.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.8 tests=BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS,SPF_NEUTRAL autolearn=ham version=3.2.5 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by lists.samba.org (Postfix) with ESMTP id C298B46664 for ; Fri, 26 Mar 2010 08:25:52 -0600 (MDT) Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o2QEPphZ025301 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 26 Mar 2010 10:25:51 -0400 Received: from localhost.localdomain (vpn-10-105.rdu.redhat.com [10.11.10.105]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o2QEPdCn026868 for ; Fri, 26 Mar 2010 10:25:51 -0400 From: Jeff Layton To: linux-cifs-client@lists.samba.org Date: Fri, 26 Mar 2010 10:25:41 -0400 Message-Id: <1269613542-6402-19-git-send-email-jlayton@samba.org> In-Reply-To: <1269613542-6402-1-git-send-email-jlayton@samba.org> References: <1269613542-6402-1-git-send-email-jlayton@samba.org> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 Subject: [linux-cifs-client] [PATCH 18/19] mount.cifs: drop capabilities if libcap is available X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-cifs-client-bounces@lists.samba.org Errors-To: linux-cifs-client-bounces@lists.samba.org From: Jeff Layton 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 --- 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], [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 #include #include +#ifdef HAVE_LIBCAP +#include +#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);