All of lore.kernel.org
 help / color / mirror / Atom feed
* [Openvpn-devel] [PATCH] Retain CAP_NET_ADMIN when dropping privileges
@ 2022-03-29 19:29 Timo Rothenpieler
  2022-03-29 23:45 ` Timo Rothenpieler
                   ` (4 more replies)
  0 siblings, 5 replies; 43+ messages in thread
From: Timo Rothenpieler @ 2022-03-29 19:29 UTC (permalink / raw)
  To: openvpn-devel

---
This patch sits on top of the current dco branch, and will not apply to
latest master.

It solves the issue of dropping root privileges breaking dco and sitnl
due to missing NET_ADMIN capabilities.


 configure.ac           |  3 ++
 src/openvpn/init.c     | 22 +++++++++++++-
 src/openvpn/platform.c | 65 +++++++++++++++++++++++++++++++++++++++++-
 src/openvpn/platform.h |  2 +-
 4 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7199483a..220c63e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -710,6 +710,9 @@ if test -z "${LIBPAM_LIBS}"; then
 	)
 fi
 
+AC_CHECK_HEADERS([linux/capability.h sys/syscall.h sys/prctl.h],
+                 [AC_DEFINE(HAVE_LINUX_CAPABILITIES, 1, [Linux capability support available])])
+
 case "${with_mem_check}" in
 	valgrind)
 		AC_CHECK_HEADERS(
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 8818ba6f..13c07ff0 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1138,6 +1138,25 @@ possibly_become_daemon(const struct options *options)
     return ret;
 }
 
+/*
+ * Determine if we need to retain process capabilities. DCO and SITNL need it.
+ * Enforce it for DCO, but only try and soft-fail for SITNL to keep backwards compat.
+ */
+static int
+get_need_keep_caps(struct context *c)
+{
+    if (dco_enabled(&c->options))
+    {
+        return 1;
+    }
+
+#ifdef ENABLE_SITNL
+    return -1;
+#else
+    return 0;
+#endif
+}
+
 /*
  * Actually do UID/GID downgrade, chroot and SELinux context switching, if requested.
  */
@@ -1167,8 +1186,9 @@ do_uid_gid_chroot(struct context *c, bool no_delay)
         {
             if (no_delay)
             {
+                int keep_caps = get_need_keep_caps(c);
                 platform_group_set(&c0->platform_state_group);
-                platform_user_set(&c0->platform_state_user);
+                platform_user_set(&c0->platform_state_user, keep_caps);
             }
             else if (c->first_time)
             {
diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c
index 450f28ba..680ebb5f 100644
--- a/src/openvpn/platform.c
+++ b/src/openvpn/platform.c
@@ -43,6 +43,12 @@
 #include <direct.h>
 #endif
 
+#ifdef HAVE_LINUX_CAPABILITIES
+#include <linux/capability.h>
+#include <sys/syscall.h>
+#include <sys/prctl.h>
+#endif
+
 /* Redefine the top level directory of the filesystem
  * to restrict access to files for security */
 void
@@ -91,17 +97,74 @@ platform_user_get(const char *username, struct platform_state_user *state)
     return ret;
 }
 
+#ifdef HAVE_LINUX_CAPABILITIES
+#define SET_CAP_HELPER(data, set, cap) data[(cap)>>5].set |= 1<<((cap)&31)
+
+static bool
+do_keep_caps(bool prepare)
+{
+    struct __user_cap_header_struct cap_hdr = { _LINUX_CAPABILITY_VERSION_3 };
+    struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3] = {};
+
+    if (syscall(SYS_capget, &cap_hdr, cap_data) < 0)
+    {
+        msg(M_NONFATAL | M_ERRNO, "failed getting capabilities");
+        return false;
+    }
+
+    if (prepare)
+    {
+        SET_CAP_HELPER(cap_data, permitted, CAP_NET_ADMIN);
+    }
+    else
+    {
+        SET_CAP_HELPER(cap_data, effective, CAP_NET_ADMIN);
+    }
+
+    if (syscall(SYS_capset, &cap_hdr, cap_data) < 0)
+    {
+        msg(M_NONFATAL | M_ERRNO, "failed setting %s capabilities", prepare ? "permitted" : "effective");
+        return false;
+    }
+
+    if (prepare && prctl(PR_SET_KEEPCAPS, 1) < 0)
+    {
+        msg(M_NONFATAL | M_ERRNO, "failed setting keepcaps");
+        return false;
+    }
+
+    return true;
+}
+#else
+static bool
+do_keep_caps(bool prepare)
+{
+    return false;
+}
+#endif
+
 void
-platform_user_set(const struct platform_state_user *state)
+platform_user_set(const struct platform_state_user *state, int keep_caps)
 {
 #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID)
     if (state->username && state->pw)
     {
+        bool caps_prepared = keep_caps && do_keep_caps(true);
+
         if (setuid(state->pw->pw_uid))
         {
             msg(M_ERR, "setuid('%s') failed", state->username);
         }
         msg(M_INFO, "UID set to %s", state->username);
+
+        if (caps_prepared && do_keep_caps(false))
+        {
+            msg(M_INFO, "Capabilities retained");
+        }
+        else if (keep_caps > 0)
+        {
+            msg(M_FATAL, "Failed retaining capabilities");
+        }
     }
 #endif
 }
diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h
index a3eec298..ef06da93 100644
--- a/src/openvpn/platform.h
+++ b/src/openvpn/platform.h
@@ -79,7 +79,7 @@ struct platform_state_group {
 
 bool platform_user_get(const char *username, struct platform_state_user *state);
 
-void platform_user_set(const struct platform_state_user *state);
+void platform_user_set(const struct platform_state_user *state, int keep_caps);
 
 bool platform_group_get(const char *groupname, struct platform_state_group *state);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2022-08-17 15:31 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-29 19:29 [Openvpn-devel] [PATCH] Retain CAP_NET_ADMIN when dropping privileges Timo Rothenpieler
2022-03-29 23:45 ` Timo Rothenpieler
2022-03-30  8:51 ` David Sommerseth
2022-03-30  9:11   ` David Sommerseth
2022-03-30 11:31     ` Timo Rothenpieler
2022-03-30 11:57       ` Gert Doering
2022-03-30 12:16         ` Antonio Quartulli
2022-03-30 15:05     ` Timo Rothenpieler
2022-03-30 20:55 ` [Openvpn-devel] [PATCH v2] " Timo Rothenpieler
2022-03-31  6:53   ` Jan Just Keijser
2022-03-31 10:06     ` David Sommerseth
2022-03-31 10:17       ` Arne Schwabe
2022-03-31 11:02       ` Gert Doering
2022-03-31 11:29         ` Timo Rothenpieler
2022-03-31 11:34           ` Gert Doering
2022-03-31 11:39             ` David Sommerseth
2022-03-31 13:20   ` David Sommerseth
2022-03-31 13:26     ` Gert Doering
2022-03-31 14:38       ` David Sommerseth
2022-03-31 14:54         ` Gert Doering
2022-04-06  9:52   ` Antonio Quartulli
2022-04-06 12:44     ` Timo Rothenpieler
2022-04-06 13:34       ` David Sommerseth
2022-04-06 13:41       ` David Sommerseth
2022-04-07 18:40   ` [Openvpn-devel] [PATCH v3] platform: " Timo Rothenpieler
2022-04-08  9:35     ` Gert Doering
2022-04-08 11:18       ` Timo Rothenpieler
2022-04-08 11:25         ` Antonio Quartulli
2022-04-18 13:29 ` [Openvpn-devel] [PATCH] " Timo Rothenpieler
2022-05-14 10:37 ` [Openvpn-devel] [PATCH v5] " Timo Rothenpieler
2022-08-10 13:57   ` Timo Rothenpieler
2022-08-11  9:30   ` Frank Lichtenheld
2022-08-11 10:03   ` [Openvpn-devel] [PATCH applied] " Gert Doering
2022-08-11 11:29     ` Gert Doering
2022-08-15  9:54     ` Gert Doering
2022-08-15 10:14       ` Timo Rothenpieler
2022-08-15 10:29         ` Gert Doering
2022-08-15 10:40           ` Timo Rothenpieler
2022-08-15 10:48             ` Gert Doering
2022-08-16  9:16               ` Steffan Karger
2022-08-16  9:33                 ` Gert Doering
2022-08-16  9:29       ` Gert Doering
2022-08-17 15:31       ` Gert Doering

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.