Skip to contentSkip to conversation

systemd: Intermediate --chroot fix with the new sd_notify() implementation

PATCH In review David Sommerseth 4 participants 11 messages Dec 7, 2016 – Dec 10, 2016

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 systemd: Intermediate --chroot fix with the new sd_notify() implementation

Commit c5931897ae8d663e7e introduced support for talking directly to the systemd service manager about the situation for the OpenVPN tunnel. This approach makes a lot of sense and is mostly the proper way to do it. But it was discovered that it breaks OpenVPN configurations using --chroot.

The reason sd_notify() calls fails when using chroot() is that sd_notify() expects to have access to a file as declared in the $NOTIFY_SOCKET environment variable. It is the main systemd instance which is responsible to provide both the environment variable as well as the socket file sd_nodify() should use. When --chroot comes into play, the $NOTIFY_SOCKET file will not be available for OpenVPN any more.

As things are getting close to the 2.4_rc2 release we will not dare to bring a too invasive fix. As well we need some time to discuss an approrpriate solution. So this intermediate fix will only provide a "successful start" message to the systemd service manager right before chroot() happens. This will at least resolve the issue in a safe and non-intrusive way.

---
 src/openvpn/init.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
src/openvpn/init.c +21 -1
index 74f1139..e47f0d4 100644
@@ -967,7 +967,27 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
       if (c->options.chroot_dir)
 	{
 	  if (no_delay)
-	    platform_chroot (c->options.chroot_dir);
+            {
+#ifdef ENABLE_SYSTEMD
+              /* If OpenVPN is started by systemd, the OpenVPN process needs
+               * to provide a preliminary status report to systemd.  This is
+               * needed as $NOTIFY_SOCKET will not be available inside the
+               * chroot, which sd_notify()/sd_notifyf() depends on.
+               *
+               * This approach is the simplest and the most non-intrusive
+               * solution right before the 2.4_rc2 release.
+               *
+               * TODO: Consider altnernative solutions - bind mount?
+               * systemd does not grok OpenVPN configuration files, thus cannot
+               * have a sane way to know if OpenVPN will chroot or not and to
+               * which subdirectory it will chroot into.
+               */
+              sd_notifyf(0, "READY=1\n"
+                "STATUS=Entering chroot, most of the init completed successfully\n"
+                "MAINPID=%lu", (unsigned long) getpid());
+#endif
+              platform_chroot (c->options.chroot_dir);
+            }
 	  else if (c->first_time)
 	    msg (M_INFO, "NOTE: chroot %s", why_not);
 	}
Signature · 1 line
1.8.3.1
#1 lore raw

David Sommerseth <[email protected]...> on Wed, 2016/12/07 03:51:

Quoted 57 lines

Commit c5931897ae8d663e7e introduced support for talking directly to the systemd service manager about the situation for the OpenVPN tunnel. This approach makes a lot of sense and is mostly the proper way to do it. But it was discovered that it breaks OpenVPN configurations using --chroot.

The reason sd_notify() calls fails when using chroot() is that sd_notify() expects to have access to a file as declared in the $NOTIFY_SOCKET environment variable. It is the main systemd instance which is responsible to provide both the environment variable as well as the socket file sd_nodify() should use. When --chroot comes into play, the $NOTIFY_SOCKET file will not be available for OpenVPN any more.

As things are getting close to the 2.4_rc2 release we will not dare to bring a too invasive fix. As well we need some time to discuss an approrpriate solution. So this intermediate fix will only provide a "successful start" message to the systemd service manager right before chroot() happens. This will at least resolve the issue in a safe and non-intrusive way.

---
 src/openvpn/init.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
src/openvpn/init.c +3 -1
index 74f1139..e47f0d4 100644
@@ -967,7 +967,27 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
       if (c->options.chroot_dir)
 	{
 	  if (no_delay)
-	    platform_chroot (c->options.chroot_dir);
+            {
+#ifdef ENABLE_SYSTEMD
+              /* If OpenVPN is started by systemd, the OpenVPN process

needs
+ * to provide a preliminary status report to systemd. This
is

src/openvpn/init.c +8 -0
+               * needed as $NOTIFY_SOCKET will not be available inside the
+               * chroot, which sd_notify()/sd_notifyf() depends on.
+               *
+               * This approach is the simplest and the most non-intrusive
+               * solution right before the 2.4_rc2 release.
+               *
+               * TODO: Consider altnernative solutions - bind mount?
+               * systemd does not grok OpenVPN configuration files, thus

cannot
+ * have a sane way to know if OpenVPN will chroot or not and
to

src/openvpn/init.c +4 -0
+               * which subdirectory it will chroot into.
+               */
+              sd_notifyf(0, "READY=1\n"
+                "STATUS=Entering chroot, most of the init completed

successfully\n"

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 993

Quoted 7 lines
src/openvpn/init.c +4 -0
+                "MAINPID=%lu", (unsigned long) getpid());
+#endif
+              platform_chroot (c->options.chroot_dir);
+            }
 	  else if (c->first_time)
 	    msg (M_INFO, "NOTE: chroot %s", why_not);
 	}

Looks good to me, so: ACK

In long term we should think about a proper solution. Notification socket is /run/systemd/notify, so we would have to make that available from within the chroot.

BTW, feel free to CC me on systemd related topics.

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#2 lore raw

Christian Hesse <[email protected]...> on Fri, 2016/12/09 18:37:

Quoted 69 lines

David Sommerseth <[email protected]...> on Wed, 2016/12/07 03:51:

Quoted 58 lines

Commit c5931897ae8d663e7e introduced support for talking directly to the systemd service manager about the situation for the OpenVPN tunnel. This approach makes a lot of sense and is mostly the proper way to do it. But it was discovered that it breaks OpenVPN configurations using --chroot.

The reason sd_notify() calls fails when using chroot() is that sd_notify() expects to have access to a file as declared in the $NOTIFY_SOCKET environment variable. It is the main systemd instance which is responsible to provide both the environment variable as well as the socket file sd_nodify() should use. When --chroot comes into play, the $NOTIFY_SOCKET file will not be available for OpenVPN any more.

As things are getting close to the 2.4_rc2 release we will not dare to bring a too invasive fix. As well we need some time to discuss an approrpriate solution. So this intermediate fix will only provide a "successful start" message to the systemd service manager right before chroot() happens. This will at least resolve the issue in a safe and non-intrusive way.

---
 src/openvpn/init.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
src/openvpn/init.c +3 -1
index 74f1139..e47f0d4 100644
@@ -967,7 +967,27 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
       if (c->options.chroot_dir)
 	{
 	  if (no_delay)
-	    platform_chroot (c->options.chroot_dir);
+            {
+#ifdef ENABLE_SYSTEMD
+              /* If OpenVPN is started by systemd, the OpenVPN process

needs
+ * to provide a preliminary status report to systemd. This
is
+ * needed as $NOTIFY_SOCKET will not be available inside
the

src/openvpn/init.c +7 -0
+               * chroot, which sd_notify()/sd_notifyf() depends on.
+               *
+               * This approach is the simplest and the most non-intrusive
+               * solution right before the 2.4_rc2 release.
+               *
+               * TODO: Consider altnernative solutions - bind mount?
+               * systemd does not grok OpenVPN configuration files, thus

cannot
+ * have a sane way to know if OpenVPN will chroot or not
and to

src/openvpn/init.c +4 -0
+               * which subdirectory it will chroot into.
+               */
+              sd_notifyf(0, "READY=1\n"
+                "STATUS=Entering chroot, most of the init completed

successfully\n"

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 993

Quoted 7 lines
src/openvpn/init.c +4 -0
+                "MAINPID=%lu", (unsigned long) getpid());
+#endif
+              platform_chroot (c->options.chroot_dir);
+            }
 	  else if (c->first_time)
 	    msg (M_INFO, "NOTE: chroot %s", why_not);
 	}  

Looks good to me, so: ACK

Quoted 3 lines

In long term we should think about a proper solution. Notification socket is /run/systemd/notify, so we would have to make that available from within the chroot.

BTW, systemd used to use abstract sockets for notifications, which worked with processes that chroot themselves. This was changed [0] in favor to PrivateNetwork setting. Private network (in terms of systemd) is nothing we can make use of, though. Obviously... :-p

Does it make sense to deny to chroot when running from systemd and instead add some more security features to the systemd unit? Things like ProtectSystem=strict, ProtectHome=true and friends. See systemd.exec(5) [1] for details.

[0]
https://github.com/systemd/systemd/commit/7181dbdb2e3112858d62bdaea4f0ad2ed685ccba
[1] https://www.freedesktop.org/software/systemd/man/systemd.exec.html

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#3 lore raw
Quoted 69 lines · Christian Hesse

Christian Hesse <[email protected]...> on Fri, 2016/12/09 18:37:

Quoted 68 lines

David Sommerseth <[email protected]...> on Wed, 2016/12/07 03:51:

Quoted 58 lines

Commit c5931897ae8d663e7e introduced support for talking directly to the systemd service manager about the situation for the OpenVPN tunnel. This approach makes a lot of sense and is mostly the proper way to do it. But it was discovered that it breaks OpenVPN configurations using --chroot.

The reason sd_notify() calls fails when using chroot() is that sd_notify() expects to have access to a file as declared in the $NOTIFY_SOCKET environment variable. It is the main systemd instance which is responsible to provide both the environment variable as well as the socket file sd_nodify() should use. When --chroot comes into play, the $NOTIFY_SOCKET file will not be available for OpenVPN any more.

As things are getting close to the 2.4_rc2 release we will not dare to bring a too invasive fix. As well we need some time to discuss an approrpriate solution. So this intermediate fix will only provide a "successful start" message to the systemd service manager right before chroot() happens. This will at least resolve the issue in a safe and non-intrusive way.

---
 src/openvpn/init.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
src/openvpn/init.c +3 -1
index 74f1139..e47f0d4 100644
@@ -967,7 +967,27 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
       if (c->options.chroot_dir)
 	{
 	  if (no_delay)
-	    platform_chroot (c->options.chroot_dir);
+            {
+#ifdef ENABLE_SYSTEMD
+              /* If OpenVPN is started by systemd, the OpenVPN process

needs
+ * to provide a preliminary status report to systemd. This
is
+ * needed as $NOTIFY_SOCKET will not be available inside
the

src/openvpn/init.c +7 -0
+               * chroot, which sd_notify()/sd_notifyf() depends on.
+               *
+               * This approach is the simplest and the most non-intrusive
+               * solution right before the 2.4_rc2 release.
+               *
+               * TODO: Consider altnernative solutions - bind mount?
+               * systemd does not grok OpenVPN configuration files, thus

cannot
+ * have a sane way to know if OpenVPN will chroot or not
and to

src/openvpn/init.c +4 -0
+               * which subdirectory it will chroot into.
+               */
+              sd_notifyf(0, "READY=1\n"
+                "STATUS=Entering chroot, most of the init completed

successfully\n"

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 993

Quoted 7 lines
src/openvpn/init.c +4 -0
+                "MAINPID=%lu", (unsigned long) getpid());
+#endif
+              platform_chroot (c->options.chroot_dir);
+            }
 	  else if (c->first_time)
 	    msg (M_INFO, "NOTE: chroot %s", why_not);
 	}  

Looks good to me, so: ACK

Thanks!

Quoted 8 lines
Quoted 3 lines

In long term we should think about a proper solution. Notification socket is /run/systemd/notify, so we would have to make that available from within the chroot.

BTW, systemd used to use abstract sockets for notifications, which worked with processes that chroot themselves. This was changed [0] in favor to PrivateNetwork setting. Private network (in terms of systemd) is nothing we can make use of, though. Obviously... :-p

:)

Quoted 4 lines

Does it make sense to deny to chroot when running from systemd and instead add some more security features to the systemd unit? Things like ProtectSystem=strict, ProtectHome=true and friends. See systemd.exec(5) [1] for details.

Yes, I think this can make sense. I would also like to see more where things are headed in regards to namespaces (or app-container, if you want). If we can also isolate the openvpn process from as much as possible from the rest of the system (and find a solution for
$HOME/.cert). But still that does provide some other challenges,
though - like: What to do with script hooks and --plugin files? And especially other dependencies of shells/interpretors and shared objects they may depend on.

Perhaps a discussion we could open up with the systemd team?

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#4 lore raw

PATCH 1/1 bind mount systemd notification socket into chroot

In reply to Christian Hesse

From: Christian Hesse <[email protected]...>

sd_notify() uses a socket to communicate with systemd. Communication fails if the socket is not available within the chroot. So bind mount the socket into the chroot when startet from systemd.

Unsharing namespace and mounting requires extra capability CAP_SYS_ADMIN.

---
 distro/systemd/[email protected]... |  2 +-
 distro/systemd/[email protected]... |  2 +-
 src/openvpn/init.c                     | 37 +++++++++++++++++++---------------
 3 files changed, 23 insertions(+), 18 deletions(-)
distro/systemd/[email protected]... +1 -1
index 5618af3..3ebd1da 100644
@@ -13,7 +13,7 @@ RuntimeDirectory=openvpn-client
 RuntimeDirectoryMode=0710
 WorkingDirectory=/etc/openvpn/client
 ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config %i.conf
-CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
+CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_ADMIN CAP_SYS_CHROOT CAP_DAC_OVERRIDE
 LimitNPROC=10
 DeviceAllow=/dev/null rw
 DeviceAllow=/dev/net/tun rw
distro/systemd/[email protected]... +1 -1
index b9b4dba..bcf1bcf 100644
@@ -13,7 +13,7 @@ RuntimeDirectory=openvpn-server
 RuntimeDirectoryMode=0710
 WorkingDirectory=/etc/openvpn/server
 ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf
-CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
+CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_ADMIN CAP_SYS_CHROOT CAP_DAC_OVERRIDE
 LimitNPROC=10
 DeviceAllow=/dev/null rw
 DeviceAllow=/dev/net/tun rw
src/openvpn/init.c +21 -16
index 26b236d..81bf9ab 100644
@@ -31,6 +31,9 @@
 #include "syshead.h"
 
 #ifdef ENABLE_SYSTEMD
+#include <string.h>
+#include <sched.h>
+#include <sys/mount.h>
 #include <systemd/sd-daemon.h>
 #endif
 
@@ -969,22 +972,24 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
 	  if (no_delay)
             {
 #ifdef ENABLE_SYSTEMD
-              /* If OpenVPN is started by systemd, the OpenVPN process needs
-               * to provide a preliminary status report to systemd.  This is
-               * needed as $NOTIFY_SOCKET will not be available inside the
-               * chroot, which sd_notify()/sd_notifyf() depends on.
-               *
-               * This approach is the simplest and the most non-intrusive
-               * solution right before the 2.4_rc2 release.
-               *
-               * TODO: Consider altnernative solutions - bind mount?
-               * systemd does not grok OpenVPN configuration files, thus cannot
-               * have a sane way to know if OpenVPN will chroot or not and to
-               * which subdirectory it will chroot into.
-               */
-              sd_notifyf(0, "READY=1\n"
-                "STATUS=Entering chroot, most of the init completed successfully\n"
-                "MAINPID=%lu", (unsigned long) getpid());
+              int fd;
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {
+                  asprintf(&chroot_notify, "%s/notify", c->options.chroot_dir);
+
+                  if (unshare(CLONE_NEWNS) != 0)
+                    msg (M_ERR, "unshare failed");
+                  if ((fd = open(chroot_notify, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
+                    msg (M_ERR, "touch failed");
+                  close(fd);
+                  if (mount(getenv("NOTIFY_SOCKET"), chroot_notify, NULL, MS_BIND, NULL) != 0)
+                    msg (M_ERR, "bind mounting notification socket failed");
+
+                  setenv("NOTIFY_SOCKET", "/notify", 1);
+                  free(chroot_notify);
+                }
 #endif
               platform_chroot (c->options.chroot_dir);
             }
Signature · 1 line
2.10.2
#5 lore raw

Re: [Openvpn-devel] [PATCH 1/1] bind mount systemd notification socket into chroot

Quoted 7 lines · Christian Hesse

From: Christian Hesse <[email protected]...>

sd_notify() uses a socket to communicate with systemd. Communication fails if the socket is not available within the chroot. So bind mount the socket into the chroot when startet from systemd.

Unsharing namespace and mounting requires extra capability CAP_SYS_ADMIN.

I will pick up this one after 2.4.0 has been released. This is a very promising approach. However, I'm not too happy about CAP_SYS_ADMIN though, that grants quite some privileges. Can we look at dropping this capability once we know we won't need it any more? Perhaps when we send READY=1?

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 980

Quoted 5 lines
src/openvpn/init.c +5 -0
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {
+                  asprintf(&chroot_notify, "%s/notify", c->options.chroot_dir);

Here we should use the buffer/string functions, based on the gc_arena implementation. Unfortunately we do not have a direct equivalent to asprintf(). A starting point would be to for example look at the string handling in print_sockaddr_ex() [socket.c:2386] or x_msg_va() [error.c:251] ... there might be better examples too, I'm just not able to remember them now :) .... buffer.[ch] keeps most of these functions.

The reason for this is basically to use the same well tested infrastructure. And with gc_arena, only a single gc_free() is required, regardless of how many buffers you allocate to that arena.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#6 lore raw

Re: [Openvpn-devel] [PATCH 1/1] bind mount systemd notification socket into chroot

David Sommerseth <[email protected]...> on Sat, 2016/12/10 01:03:

Quoted 7 lines · Christian Hesse
Quoted 6 lines

From: Christian Hesse <[email protected]...>

sd_notify() uses a socket to communicate with systemd. Communication fails if the socket is not available within the chroot. So bind mount the socket into the chroot when startet from systemd.

Quoted 8 lines
Quoted 2 lines

Unsharing namespace and mounting requires extra capability CAP_SYS_ADMIN.

I will pick up this one after 2.4.0 has been released. This is a very promising approach. However, I'm not too happy about CAP_SYS_ADMIN though, that grants quite some privileges. Can we look at dropping this capability once we know we won't need it any more? Perhaps when we send READY=1?

Never tried to drop capabilities... Have to look into that. We do no longer need CAP_SYS_ADMIN after the bind mount. (Or not at all without chrooting.)

Quoted 14 lines
Quoted 6 lines
src/openvpn/init.c +5 -0
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {
+                  asprintf(&chroot_notify, "%s/notify",

c->options.chroot_dir);

Here we should use the buffer/string functions, based on the gc_arena implementation. Unfortunately we do not have a direct equivalent to asprintf(). A starting point would be to for example look at the string handling in print_sockaddr_ex() [socket.c:2386] or x_msg_va() [error.c:251] ... there might be better examples too, I'm just not able to remember them now :) .... buffer.[ch] keeps most of these functions.

Quoted 3 lines

The reason for this is basically to use the same well tested infrastructure. And with gc_arena, only a single gc_free() is required, regardless of how many buffers you allocate to that arena.

I do not like this myself. The patch is just a proof of concept... So this should be polished before committing. ;)

Thanks for the hints, I will have a look.

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#7 lore raw

Re: [Openvpn-devel] [PATCH 1/1] bind mount systemd notification socket into chroot

Quoted 17 lines · Christian Hesse

David Sommerseth <[email protected]...> on Sat, 2016/12/10 01:03:

Quoted 7 lines · Christian Hesse
Quoted 6 lines

From: Christian Hesse <[email protected]...>

sd_notify() uses a socket to communicate with systemd. Communication fails if the socket is not available within the chroot. So bind mount the socket into the chroot when startet from systemd.

Quoted 8 lines
Quoted 2 lines

Unsharing namespace and mounting requires extra capability CAP_SYS_ADMIN.

I will pick up this one after 2.4.0 has been released. This is a very promising approach. However, I'm not too happy about CAP_SYS_ADMIN though, that grants quite some privileges. Can we look at dropping this capability once we know we won't need it any more? Perhaps when we send READY=1?

Quoted 3 lines

Never tried to drop capabilities... Have to look into that. We do no longer need CAP_SYS_ADMIN after the bind mount. (Or not at all without chrooting.)

Sounds reasonable. Since we need to take CAP_SYS_ADMIN out of the unit file regardless, we need to drop the CAP_SYS_ADMIN capability inside OpenVPN anyhow. Just need to figure out the best place for it.

As a pointer for managing capabilities, have a look at the capsetp(3) man page.

Quoted 14 lines
Quoted 14 lines
Quoted 6 lines
src/openvpn/init.c +5 -0
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {
+                  asprintf(&chroot_notify, "%s/notify",

c->options.chroot_dir);

Here we should use the buffer/string functions, based on the gc_arena implementation. Unfortunately we do not have a direct equivalent to asprintf(). A starting point would be to for example look at the string handling in print_sockaddr_ex() [socket.c:2386] or x_msg_va() [error.c:251] ... there might be better examples too, I'm just not able to remember them now :) .... buffer.[ch] keeps most of these functions.

Quoted 8 lines
Quoted 3 lines

The reason for this is basically to use the same well tested infrastructure. And with gc_arena, only a single gc_free() is required, regardless of how many buffers you allocate to that arena.

I do not like this myself. The patch is just a proof of concept... So this should be polished before committing. ;)

Thanks for the hints, I will have a look.

It's a great PoC! And good to see that we might find a solution for this. Will look forward to dig deeper into this in the coming weeks too.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#8 lore raw

Re: [Openvpn-devel] [PATCH 1/1] bind mount systemd notification socket into chroot

In reply to Christian Hesse

Hi,

Quoted 5 lines · Christian Hesse
src/openvpn/init.c +5 -0
+              int fd;
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 989

Quoted 10 lines
src/openvpn/init.c +10 -0
+                  asprintf(&chroot_notify, "%s/notify", c->options.chroot_dir);
+
+                  if (unshare(CLONE_NEWNS) != 0)
+                    msg (M_ERR, "unshare failed");
+                  if ((fd = open(chroot_notify, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
+                    msg (M_ERR, "touch failed");
+                  close(fd);
+                  if (mount(getenv("NOTIFY_SOCKET"), chroot_notify, NULL, MS_BIND, NULL) != 0)
+                    msg (M_ERR, "bind mounting notification socket failed");
+

This is WAY over the top of what should go into OpenVPN code. Really.

NAK on approach, NAK on code.

Is there a way make sd_notify() behave like syslog()? That is, you call something like "openlog()" which will acquire the necessary file descriptor and then you can afterwards chroot() to your heart's content and do not need access to the actual socket file anymore (because openlog() will keep it around for syslog() to use).

If sd_notify() cannot be taught to do that, either do what David proposed (disable chroot if running under systemd), or at least move that code out of init.c into something like platform.c.

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#9 lore raw

Re: [Openvpn-devel] [PATCH 1/1] bind mount systemd notification socket into chroot

Quoted 21 lines · Gert Doering

Hi,

Quoted 5 lines · Christian Hesse
src/openvpn/init.c +5 -0
+              int fd;
+              char * chroot_notify = NULL;
+
+              if (sd_notify(0, "READY=0") > 0)
+                {

src/openvpn/init.c do_uid_gid_chroot (struct context *c, bool no_delay) · line 989

Quoted 10 lines
src/openvpn/init.c +10 -0
+                  asprintf(&chroot_notify, "%s/notify", c->options.chroot_dir);
+
+                  if (unshare(CLONE_NEWNS) != 0)
+                    msg (M_ERR, "unshare failed");
+                  if ((fd = open(chroot_notify, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
+                    msg (M_ERR, "touch failed");
+                  close(fd);
+                  if (mount(getenv("NOTIFY_SOCKET"), chroot_notify, NULL, MS_BIND, NULL) != 0)
+                    msg (M_ERR, "bind mounting notification socket failed");
+

This is WAY over the top of what should go into OpenVPN code. Really.

Quoted 8 lines

NAK on approach, NAK on code.

Is there a way make sd_notify() behave like syslog()? That is, you call something like "openlog()" which will acquire the necessary file descriptor and then you can afterwards chroot() to your heart's content and do not need access to the actual socket file anymore (because openlog() will keep it around for syslog() to use).

First of all, bind mounts are fairly common in Linux these days - especially when you start to try to chroot/containerize (including docker)/"jail" and otherwise isolate applications. Chroots in general are considered a bit too easy to escape from, unless privileges are dropped at the right point. Namespaces and other container techniques are often somewhat better, but still does not yet provide the full isolation many expects. In this context bind mounts are often considered simpler and to some degree safer than a full mount of /dev, /proc, /sys, /run and so on.

Unfortunately, there exists no "openlog()" equivalent to my knowledge for sd_notify() and other functions depending on the /run/systemd directory. But it's a good idea, and in fact such a "prepare for chroot" in libsystemd could probably do such a bind mount for the caller. I have a good contact with one of the upstream systemd developers and will discuss this with him ... so with time, we might have something better.

Well, there is one feature systemd guys might throw at us instantly when we open this topic ... PrivateNetwork=true in the unit file. But that is useless for OpenVPN as then we will only have access to the lo network device, all other network devices are unavailable.

Quoted 3 lines

If sd_notify() cannot be taught to do that, either do what David proposed (disable chroot if running under systemd), or at least move that code out of init.c into something like platform.c.

That's a fair argument. As long as thelibsystemd shipped in RHEL7 does not, to our knowledge, carry such a feature which we need; implementing this functionality inside platform.c is reasonable.

What I am wondering then is if we should implement platform_chroot() which is called from init.c. Where it will just call chroot() on non-systemd and non-Windows systems. When systemd is enabled and detected detected it will prepare the bind mount, drop capabilities and then call chroot().

Is that a reasonable approach? Or would you prefer to have just the bind mount stuff isolated into platform.c?

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#10 lore raw
In reply to David Sommerseth

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Your patch has been applied to the master branch

commit 65140a3acfa42e5d42cdfcf8108f00a62d5767ff

Author: David Sommerseth
Date:   Wed Dec 7 03:51:52 2016 +0100
     systemd: Intermediate --chroot fix with the new sd_notify() implementation

     Signed-off-by: David Sommerseth <[email protected]...>
     Acked-by: Christian Hesse <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg13416.html

- --
kind regards,

David Sommerseth

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJYSyTlAAoJEIbPlEyWcf3y/sMQAMaJhmd4WJjjr7am+6SqMyWg pk7J4FzysRu8Dm/czDEULAriDO6YDMrVN/HNO3z/tLxUKnwvP1Qq9RbzM1HwDHbH 3vuVFu/Id4GGwiVqu35LsOq0dVwLra188L709AgTqepCXCuajUxSDtl8lcTCL2vN gDTL0FiYQSTl/jAlMKAeFg8W8C5pFDPOUumBgcYNdqqwW7FUPsl5JYqZup9bqgPO cuY5kSx8GUe7En1EPSbGIdX/cVwkHDtxs9Caqpr1Qb0d8iinchDCaz8YrYDjvpkG j1NE32lNbWLpeiXP2hLN9YIg+V7TSuT1jCyUwKJUEt/y0dZxdlpfeyS52WAGVTZY BaRmnzdGHmdYbSSv8ft1qKh6NI/3sRfmSzd2+eb9dTC2FsUUSoprU0yAISYR+dew Jvp8jeE/F4xUGKp6ierMkzvmqtudQRrq3hkmtbpS1CaM2Pf+uugQ7Z3s7rk+GRwb 2E0YpzKQNheeTsbInQWJQoXLZx75anQUu8uVl9IA8uabLSNJdzCfik2Mjbzs7/Kc hDJ4S0eJGIp2R7PWJUj0KdLyEP5853fGof6pfc1m8e0GCI/WCbPkEg7nRE6fqrXL n92sFCzVq8z8Ad6Up0CEB3lxW9purT39QVtvd56N9D2M8i8OMydIOOoZA0iQeBuI GcuJ6EC98Ul19QPdFCrk
=YYaa
-----END PGP SIGNATURE-----