[ovs-dev] [PATCH RFC] ovs-vswitchd: Drop all capabilities that OVS doesn't need.

Ben Pfaff blp at nicira.com
Wed Jul 23 00:07:20 UTC 2014


Signed-off-by: Ben Pfaff <blp at nicira.com>
---
ovs-vswitchd typically runs as root, but it doesn't need most of the powers
of root.  This commit makes it drop all the capabilities that it doesn't
typically need.

I don't know how capabilities are really used in practice.  Something
equivalent could be achieved through the file system.  I don't know the
preferred way to do it.

diff --git a/configure.ac b/configure.ac
index 971c7b3..9665516 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,7 @@ OVS_CHECK_COVERAGE
 OVS_CHECK_NDEBUG
 OVS_CHECK_NETLINK
 OVS_CHECK_OPENSSL
+OVS_CHECK_LIBCAP
 OVS_CHECK_LOGDIR
 OVS_CHECK_PYTHON
 OVS_CHECK_PYTHON_COMPAT
diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4
index 26b8058..6017c74 100644
--- a/m4/openvswitch.m4
+++ b/m4/openvswitch.m4
@@ -192,6 +192,15 @@ AC_DEFUN([OVS_CHECK_BACKTRACE],
                   [AC_DEFINE([HAVE_BACKTRACE], [1],
                              [Define to 1 if you have backtrace(3).])])])
 
+dnl Defines HAVE_LIBCAP if libcap and <sys/capability.h> are available.
+AC_DEFUN([OVS_CHECK_LIBCAP],
+  [AC_CHECK_HEADER([sys/capability.h],
+    [AC_SEARCH_LIBS([cap_get_proc], [cap])
+     if test $ac_cv_search_cap_get_proc != no; then
+       AC_DEFINE([HAVE_LIBCAP], [1], 
+                 [Define to 1 if you have libcap and <sys/capability.h>.])
+     fi])])
+
 dnl Checks for valgrind/valgrind.h.
 AC_DEFUN([OVS_CHECK_VALGRIND],
   [AC_CHECK_HEADERS([valgrind/valgrind.h])])
diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
index 3c843e1..6625cd7 100644
--- a/vswitchd/ovs-vswitchd.c
+++ b/vswitchd/ovs-vswitchd.c
@@ -49,6 +49,9 @@
 #include "vlog.h"
 #include "lib/vswitch-idl.h"
 #include "lib/netdev-dpdk.h"
+#ifdef HAVE_LIBCAP
+#include <sys/capability.h>
+#endif
 
 VLOG_DEFINE_THIS_MODULE(vswitchd);
 
@@ -60,6 +63,7 @@ static unixctl_cb_func ovs_vswitchd_exit;
 
 static char *parse_options(int argc, char *argv[], char **unixctl_path);
 static void usage(void) NO_RETURN;
+static void drop_capabilities(void);
 
 int
 main(int argc, char *argv[])
@@ -75,6 +79,8 @@ main(int argc, char *argv[])
     argc -= retval;
     argv += retval;
 
+    drop_capabilities();
+
     proctitle_init(argc, argv);
     service_start(&argc, &argv);
     remote = parse_options(argc, argv, &unixctl_path);
@@ -265,3 +271,77 @@ ovs_vswitchd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
     *exiting = true;
     unixctl_command_reply(conn, NULL);
 }
+
+static void
+drop_capabilities(void)
+{
+#ifdef HAVE_LIBCAP
+    /* Capabilities we'd like to retain, if we have them. */
+    static const cap_value_t keep[] = {
+        CAP_IPC_LOCK, CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_NET_RAW
+    };
+
+    cap_t cur, next;
+    char *s;
+    int i;
+
+    /* Get current capabilities. */
+    cur = cap_get_proc();
+    if (!cur) {
+        VLOG_FATAL("failed to retrieve process capabilities (%s)",
+                   ovs_strerror(errno));
+    }
+
+    /* Get empty capability. */
+    next = cap_init();
+    if (!next) {
+        VLOG_FATAL("failed to create capability set (%s)",
+                   ovs_strerror(errno));
+    }
+
+    /* Copy the capabilities that we want to keep from 'cur' to 'next'.
+     * Leave other capabilities unset.
+     * Thus, 'keep' is effectively a whitelist; we drop all other
+     * capabilities. */
+    for (i = 0; i < ARRAY_SIZE(keep); i++) {
+        static const int flags[] = {
+            CAP_EFFECTIVE, CAP_INHERITABLE, CAP_PERMITTED
+        };
+        cap_value_t value = keep[i];
+        int j;
+
+        for (j = 0; j < ARRAY_SIZE(flags); j++) {
+            cap_flag_t flag = flags[j];
+            cap_flag_value_t flag_value;
+
+            if (cap_get_flag(cur, value, flags[j], &flag_value)) {
+                VLOG_FATAL("failed to get capability flag (%s)",
+                           ovs_strerror(errno));
+            }
+            if (cap_set_flag(next, flag, 1, &value, flag_value)) {
+                VLOG_FATAL("failed to set capability flag (%s)",
+                           ovs_strerror(errno));
+            }
+        }
+    }
+
+    /* Set our capability set to 'next'. */
+    if (cap_set_proc(next)) {
+        VLOG_FATAL("failed to set process capabilities (%s)",
+                   ovs_strerror(errno));
+    }
+
+    /* Log that we dropped capabilities. */
+    s = cap_to_text(next, NULL);
+    if (!s) {
+        VLOG_FATAL("failed to convert capabilities to text (%s)",
+                   ovs_strerror(errno));
+    }
+    VLOG_INFO("reduced capability set to: %s", s);
+
+    /* Clean up. */
+    cap_free(s);
+    cap_free(cur);
+    cap_free(next);
+#endif  /* HAVE_LIBCAP */
+}
-- 
1.7.10.4




More information about the dev mailing list