[ovs-dev] [v3 03/10] lib/daemon: add option to retain CAP_NET_ADMIN capability

Andy Zhou azhou at nicira.com
Mon Sep 14 22:54:07 UTC 2015


This patch adds an argument to daemon_become_new_user() API for the
caller specify whether the capability of accessing the kernel datapath
is needed. On Linux, daemons access the kernel datapath need to
retain some root privileges, such as CAP_NET_ADMIN.

Current implementation (of retaining CAP_NET_ADMIN) requires libcap-ng.
This implementation only covers the Linux.
Other Unix platforms currently do not support kernel based datapath.
(but supports --user options for all daemons.)
On Windows, daemon_become_new_user() is a stub function that does
nothing.

Signed-off-by: Andy Zhou <azhou at nicira.com>
---
 lib/daemon-unix.c | 38 +++++++++++++++++++++++++++++++++++---
 lib/daemon.h      |  5 ++---
 2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/lib/daemon-unix.c b/lib/daemon-unix.c
index f175037..f361165 100644
--- a/lib/daemon-unix.c
+++ b/lib/daemon-unix.c
@@ -27,6 +27,9 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#if HAVE_LIBCAPNG
+#include <cap-ng.h>
+#endif
 #include "command-line.h"
 #include "fatal-signal.h"
 #include "dirs.h"
@@ -748,8 +751,28 @@ daemon_switch_user(const uid_t real, const uid_t effective, const uid_t saved,
     }
 }
 
+static void
+daemon_become_new_user_with_datapath_capability(void)
+{
+#if HAVE_LIBCAPNG
+    if (capng_have_capabilities(CAPNG_SELECT_CAPS) > CAPNG_NONE) {
+        capng_clear(CAPNG_SELECT_BOTH);
+        capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
+                     CAP_NET_ADMIN);
+        if (capng_change_id(uid, gid,
+                            CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) {
+            VLOG_FATAL("%s: libcap-ng fail to switch to user and group "
+                       "%d:%d, aborting", pidfile, uid, gid);
+        }
+    }
+#else
+    VLOG_FATAL("%s: fail to downgrade user using libcap-ng. (libcap-ng is "
+               "not configured at compile time.) aborting", pidfile);
+#endif
+}
+
 void
-daemon_become_new_user(void)
+daemon_become_new_user(bool access_kernel_datapath)
 {
     /* "Setuid Demystified" by Hao Chen, etc outlines some caveats of
      * around unix system call setuid() and friends. This implementation
@@ -769,11 +792,20 @@ daemon_become_new_user(void)
      * according to the paper above.)   */
 
     if (switch_to_new_user) {
+
+        if (access_kernel_datapath) {
+            daemon_become_new_user_with_datapath_capability();
+            return;
+        }
+
+        /* Using more portable APIs to switch uid:gid, when datapath
+         * access is not required.  On Linux systems, all capabilities
+         * will be dropped.  */
         daemon_switch_group(gid, gid, gid);
 
         if (user && initgroups(user, gid) == -1) {
-            VLOG_FATAL("%s: fail to add supplementary group gid %d, aborting",
-                       pidfile, gid);
+            VLOG_FATAL("%s: fail to add supplementary group gid %d, "
+                       "aborting", pidfile, gid);
         }
         daemon_switch_user(uid, uid, uid, user);
     }
diff --git a/lib/daemon.h b/lib/daemon.h
index fdd7b6a..f98ef16 100644
--- a/lib/daemon.h
+++ b/lib/daemon.h
@@ -76,7 +76,7 @@ void set_detach(void);
 void daemon_set_monitor(void);
 void set_no_chdir(void);
 void ignore_existing_pidfile(void);
-void daemon_become_new_user(void);
+void daemon_become_new_user(bool access_kernel_datapath);
 pid_t read_pidfile(const char *name);
 #else
 #define DAEMON_OPTION_ENUMS                    \
@@ -120,11 +120,10 @@ void control_handler(DWORD request);
 void set_pipe_handle(const char *pipe_handle);
 
 static inline void
-daemon_become_new_user(void)
+daemon_become_new_user(bool access_kernel_datapath OVS_UNUSED)
 {
     /* Not implemented. */
 }
-
 #endif /* _WIN32 */
 
 bool get_detach(void);
-- 
1.9.1




More information about the dev mailing list