]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added "setcon" directive for interoperability with SELinux
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Fri, 4 Sep 2009 23:50:35 +0000 (23:50 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Fri, 4 Sep 2009 23:50:35 +0000 (23:50 +0000)
(Sebastien Raveau).

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@4932 e7ae566f-a301-0410-adde-c780ea21d3b5

configure.ac
init.c
openvpn.8
options.c
options.h
syshead.h

index ae40458fb1ababa6975ef3c478605162b60b395d..116ff7c9bc15d05314d0eedd107189b28591cf28 100644 (file)
@@ -206,6 +206,12 @@ AC_ARG_ENABLE(strict-options,
    [STRICT_OPTIONS="no"]
 )
 
+AC_ARG_ENABLE(selinux,
+   [  --disable-selinux       Disable SELinux support],
+   [SELINUX="$enableval"],
+   [SELINUX="yes"]
+)
+
 AC_ARG_WITH(ssl-headers,
    [  --with-ssl-headers=DIR  Crypto/SSL Include files location],
    [CS_HDR_DIR="$withval"]
@@ -863,6 +869,23 @@ if test "$PASSWORD_SAVE" = "yes"; then
    AC_DEFINE(ENABLE_PASSWORD_SAVE, 1, [Allow --askpass and --auth-user-pass passwords to be read from a file])
 fi
 
+dnl
+dnl check for SELinux library and headers
+dnl
+if test "$SELINUX" = "yes"; then
+   AC_CHECKING([for libselinux Library and Header files])
+   AC_CHECK_HEADER(selinux/selinux.h,
+      [AC_CHECK_LIB(selinux, setcon,
+         [
+            OPENVPN_ADD_LIBS(-lselinux)
+            AC_DEFINE(HAVE_SETCON, 1, [SELinux support])
+         ],
+            [AC_MSG_RESULT([SELinux library not found.])]
+         )],
+      [AC_MSG_RESULT([SELinux headers not found.])]
+   )
+fi
+
 TAP_ID="PRODUCT_TAP_ID"
 TAP_WIN32_MIN_MAJOR="PRODUCT_TAP_WIN32_MIN_MAJOR"
 TAP_WIN32_MIN_MINOR="PRODUCT_TAP_WIN32_MIN_MINOR"
diff --git a/init.c b/init.c
index c94cfe25d518cedfa38c645eda506586c4b1811b..80b284977a0767b4dfe70bd7e6edbc0f77dc340e 100644 (file)
--- a/init.c
+++ b/init.c
@@ -667,7 +667,7 @@ possibly_become_daemon (const struct options *options, const bool first_time)
 }
 
 /*
- * Actually do UID/GID downgrade, and chroot, if requested.
+ * Actually do UID/GID downgrade, chroot and SELinux context switching, if requested.
  */
 static void
 do_uid_gid_chroot (struct context *c, bool no_delay)
@@ -697,6 +697,26 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
        {
          msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not);
        }
+
+#ifdef HAVE_SETCON
+      /* Apply a SELinux context in order to restrict what OpenVPN can do
+       * to _only_ what it is supposed to do after initialization is complete
+       * (basically just network I/O operations). Doing it after chroot
+       * requires /proc to be mounted in the chroot (which is annoying indeed
+       * but doing it before requires more complex SELinux policies.
+       */
+      if (c->options.selinux_context)
+       {
+         if (no_delay) {
+           if (-1 == setcon (c->options.selinux_context))
+             msg (M_ERR, "setcon to '%s' failed; is /proc accessible?", c->options.selinux_context);
+           else
+             msg (M_INFO, "setcon to '%s' succeeded", c->options.selinux_context);
+         }
+         else
+           msg (M_INFO, "NOTE: setcon %s", why_not);
+       }
+#endif
     }
 }
 
@@ -1964,16 +1984,20 @@ do_option_warnings (struct context *c)
   if (o->ping_send_timeout && !o->ping_rec_timeout)
     msg (M_WARN, "WARNING: --ping should normally be used with --ping-restart or --ping-exit");
 
-  if (o->username || o->groupname || o->chroot_dir)
+  if (o->username || o->groupname || o->chroot_dir
+#ifdef HAVE_SETCON
+      || o->selinux_context
+#endif
+      )
    {
     if (!o->persist_tun)
-     msg (M_WARN, "WARNING: you are using user/group/chroot without persist-tun -- this may cause restarts to fail");
+     msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail");
     if (!o->persist_key
 #ifdef ENABLE_PKCS11
        && !o->pkcs11_id
 #endif
        )
-     msg (M_WARN, "WARNING: you are using user/group/chroot without persist-key -- this may cause restarts to fail");
+     msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-key -- this may cause restarts to fail");
    }
 
   if (o->chroot_dir && !(o->username && o->groupname))
index 9f31f204d944bd824356eebfc05a1e2268fdcb19..6e2541a0476f590e59e5ec87fcf2381202da2acd 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -1889,6 +1889,39 @@ complications can result when scripts or restarts
 are executed after the chroot operation.
 .\"*********************************************************
 .TP
+.B --setcon context
+Apply SELinux
+.B context
+after initialization. This
+essentially provides the ability to restrict OpenVPN's
+rights to only network I/O operations, thanks to
+SELinux. This goes further than
+.B --user
+and
+.B --chroot
+in that those two, while being great security features,
+unfortunately do not protect against privilege escalation
+by exploitation of a vulnerable system call. You can of
+course combine all three, but please note that since
+setcon requires access to /proc you will have to provide
+it inside the chroot directory (e.g. with mount --bind).
+
+Since the setcon operation is delayed until after
+initialization, OpenVPN can be restricted to just
+network-related system calls, whereas by applying the
+context before startup (such as the OpenVPN one provided
+in the SELinux Reference Policies) you will have to
+allow many things required only during initialization.
+
+Like with chroot, complications can result when scripts
+or restarts are executed after the setcon operation,
+which is why you should really consider using the
+.B --persist-key
+and
+.B --persist-tun
+options.
+.\"*********************************************************
+.TP
 .B --daemon [progname]
 Become a daemon after all initialization functions are completed.
 This option will cause all message and error output to
index eba311b8685a9ab47462402d123fb188d9a77757..a7cab8074859c7e6758ed956b0a80a5308ed9446 100644 (file)
--- a/options.c
+++ b/options.c
@@ -265,6 +265,9 @@ static const char usage_message[] =
   "--user user     : Set UID to user after initialization.\n"
   "--group group   : Set GID to group after initialization.\n"
   "--chroot dir    : Chroot to this directory after initialization.\n"
+#ifdef HAVE_SETCON
+  "--setcon context: Apply this SELinux context after initialization.\n"
+#endif
   "--cd dir        : Change to this directory before initialization.\n"
   "--daemon [name] : Become a daemon after initialization.\n"
   "                  The optional 'name' parameter will be passed\n"
@@ -1216,6 +1219,9 @@ show_settings (const struct options *o)
   SHOW_STR (groupname);
   SHOW_STR (chroot_dir);
   SHOW_STR (cd_dir);
+#ifdef HAVE_SETCON
+  SHOW_STR (selinux_context);
+#endif
   SHOW_STR (writepid);
   SHOW_STR (up_script);
   SHOW_STR (down_script);
@@ -3710,6 +3716,13 @@ add_option (struct options *options,
        }
       options->cd_dir = p[1];
     }
+#ifdef HAVE_SETCON
+  else if (streq (p[0], "setcon") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->selinux_context = p[1];
+    }
+#endif
   else if (streq (p[0], "writepid") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
index 5b4ad8c8d4dde6b77cfa5bb2c90cbda5e329715d..8cabf09873091c46a3b7517d081c47d58527d855 100644 (file)
--- a/options.h
+++ b/options.h
@@ -253,6 +253,9 @@ struct options
   const char *groupname;
   const char *chroot_dir;
   const char *cd_dir;
+#ifdef HAVE_SETCON
+  char *selinux_context;
+#endif
   const char *writepid;
   const char *up_script;
   const char *down_script;
index b6f3c4ed9b889fb5cb7317a71492ee36fa85498d..6e81103b295ca4b6c60a17536b23bbbf31dbaebf 100644 (file)
--- a/syshead.h
+++ b/syshead.h
 #include <sys/epoll.h>
 #endif
 
+#ifdef HAVE_SETCON
+#include <selinux/selinux.h>
+#endif
+
 #ifdef TARGET_SOLARIS
 #ifdef HAVE_STRINGS_H
 #include <strings.h>