Hi David,

David Sommerseth wrote:
Hi all,

I've been reviewing a bug reported to the v2.3 code base. We're in the beta phase currently, and this is a bug I'd like to get fixed before we're moving on further. The bug is related to the use of the 'system' flag in --script-security.

<https://community.openvpn.net/openvpn/ticket/228>

The use of the 'system' flag has been deprecated for a long time. And it is really a potential security issue to use it, due to shell expansions which might happen. The preferred (and default way) is to use execve(), which is far safer and does not do the shell expansions while executing the script or binary.

on Linux the difference is not that big, however watch out for Windows servers - with the old (system) like functionality it was possible to specify e.g. a VBS script directly. With the 'exec' style you need to specify the vbscript.exe, the full path to the script etc etc. There's even an example about this in the book you're reviewed for me ;) If at all possible I'd leave in the 'system' like functionality , as it is very valuable for debugging scripts. We can add warnings about it being deprecated and the fact that there's the risk of memory leaks , but I do see value in this feature.

JM2CW,

JJK


The fix I'm currently considering is to remove support for the system() call completely. This support was introduced in 2.1_rc9 (Nov 17, 2008).

Does anyone depend on --script-security where the 'system' flag is required? If you need this feature, can you please elaborate why this support is needed and why you cannot use the preferred default with execve?

The main differences between execve() and system() calls are:

system() loads a shell before executing the script or binary, which
also provides all system environment variables defined by
/etc/profile etc.  On top of that, all the OpenVPN configured
environment variables are added.

execve() will load and execute the script or binary directly, which
will only provide the environment variables provided by OpenVPN by
default.  Example:

   -------------------------------------
   #!/bin/bash

   printenv
   -------------------------------------

Using this with '--script-security 2' will dump this out:

   -------------------------------------
   dev_type=tap
   ifconfig_local=192.168.100.1
   proto_1=udp
   tun_mtu=1500
   ifconfig_netmask=255.255.255.0
   script_type=up
   verb=4
   local_port_1=10443
   dev=tap0
   remote_port_1=10443
   PWD=/home/test/openvpn
   daemon=0
   ifconfig_broadcast=192.168.100.255
   SHLVL=1
   script_context=init
   daemon_start_time=1350465187
   daemon_pid=19045
   daemon_log_redirect=0
   link_mtu=1573
   -------------------------------------

If you need system variables as well with execve, you can either modify
the #!/bin/bash line to add --login, or you can source /etc/profile in
your script.

If you modify the --script-security to look like
'--script-security 2 system', printenv will dump a rather massive list
with environment variables.



* Technical details regarding a possible fix:

The reason this is hard to fix, is that it will require a massive work to avoid memory leaks. An first example:

   --------------------------------------------------------------------
     char *envvar = malloc(100);

     snprintf(envvar, 30, "TESTVAL=abc");
     putenv(envvar);     /* NOTE: We only do putenv() here */
     system("/bin/sh");  /* echo $TESTVAL returns 'abc' */

     snprintf(envvar, 30, "TESTVAL=123456");  /* A simple change */
     system("/bin/sh");  /* echo $TESTVAL returns '123456' */

     free(e);
     system("/bin/sh");  /* echo $TESTVAL is not set */
   --------------------------------------------------------------------

The current implementation will clean up the environment variables too early when using 'system'. When using 'execve', OpenVPN provides a the environment variables via a completely different mechanism which cleans up the memory properly at the right time.

The result is that with 'system', we're seeing assertion issues as it is now. Trying to fix this, leads easily to other fun memory corruption issues. And fixing this requires a more massive amount of adding proper gc_arena garbage collection higher up in the call paths. This is needed to let the system() call have all the environment variables set by OpenVPN untouched while running and first clean them up afterwards.

Considering that using system() is less safer than execve(), I would prefer to remove support for system(); instead of passing around a lot more gc_arena pointers to get the memory management correct for system() to function properly.

My first hackish attempt (without cleaning it up) gives this change stat:

 $ git diff --stat
 src/openvpn/misc.c     |   65 
++++++++++++++++++++++++++++++++++++++++++-----------------------
 src/openvpn/misc.h     |    6 ++++--
 src/openvpn/platform.c |    6 +++---
 src/openvpn/platform.h |    2 +-
 4 files changed, 50 insertions(+), 29 deletions(-)

I personally find that a bit too much to make a deprecated feature work.
Unless there are some strong arguments why we really do need system()

Any thoughts, ideas or suggestions are most welcome!


kind regards,

David Sommerseth

------------------------------------------------------------------------



Reply via email to