[ovs-dev] [PATCH 3/3][RFC] Implement chrooting for ovsdb-server

Eric Sesterhenn eric.sesterhenn at lsexperts.de
Fri Jul 11 11:24:08 UTC 2014



commit 9848adf57ce712c941dd41a6bf74a09d4b7e3555
Author: Eric Sesterhenn <eric.sesterhenn at lsexperts.de>
Date:   Fri Jul 11 03:56:08 2014 -0500

    Implement chrooting for ovsdb-server

    This adds the command line options --chroot-dir and --chroot-user
    to ovsdb-server, which allows to put the process into a chroot.

    Signed-off-by: Eric Sesterhenn <eric.sesterhenn at lsexperts.de>

diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index 89363c6..7043702 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -21,6 +21,13 @@
 #include <signal.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#endif

 #include "column.h"
 #include "command-line.h"
@@ -28,6 +35,7 @@
 #include "dirs.h"
 #include "dummy.h"
 #include "dynamic-string.h"
+#include "entropy.h"
 #include "fatal-signal.h"
 #include "file.h"
 #include "hash.h"
@@ -97,7 +105,8 @@ static void close_db(struct db *db);

 static void parse_options(int *argc, char **argvp[],
                           struct sset *remotes, char **unixctl_pathp,
-                          char **run_command);
+                          char **run_command,
+                          char **chroot_dir, char **chroot_user);
 static void usage(void) NO_RETURN;

 static char *reconfigure_remotes(struct ovsdb_jsonrpc_server *,
@@ -119,7 +128,7 @@ static void load_config(FILE *config_file, struct sset *remotes,
 static void
 main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
           struct unixctl_server *unixctl, struct sset *remotes,
-          struct process *run_process, bool *exiting)
+          struct process *run_process, bool *exiting, bool chroot)
 {
     char *remotes_error, *ssl_error;
     struct shash_node *node;
@@ -189,6 +198,11 @@ main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
         if (should_service_stop()) {
             *exiting = true;
         }
+#ifndef WIN32
+        if (chroot && (getppid() == 1)) {
+            *exiting = true;
+        }
+#endif
     }

 }
@@ -198,6 +212,8 @@ main(int argc, char *argv[])
 {
     char *unixctl_path = NULL;
     char *run_command = NULL;
+    char *chroot_dir = NULL;
+    char *chroot_user = NULL;
     struct unixctl_server *unixctl;
     struct ovsdb_jsonrpc_server *jsonrpc;
     struct sset remotes, db_filenames;
@@ -218,7 +234,8 @@ main(int argc, char *argv[])
     fatal_ignore_sigpipe();
     process_init();

-    parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
+    parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command,
+                  &chroot_dir, &chroot_user);

     /* Create and initialize 'config_tmpfile' as a temporary file to hold
      * ovsdb-server's most basic configuration, and then save our initial
@@ -246,6 +263,10 @@ main(int argc, char *argv[])

     save_config__(config_tmpfile, &remotes, &db_filenames);

+    if (initialize_entropy()) {
+        ovs_fatal(0, "Unable to initialize entropy source");
+    }
+
     daemonize_start();

     /* Load the saved config. */
@@ -320,7 +341,64 @@ main(int argc, char *argv[])
     unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
                              ovsdb_server_list_databases, &all_dbs);

-    main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting);
+#ifndef WIN32
+    if (chroot_dir && chroot_user && !run_command) {
+        pid_t pid;
+        struct passwd userpwd;
+        struct passwd* pwdptr = &userpwd;
+        struct passwd* tempPwdPtr;
+        char buf[200];
+        size_t buflen = sizeof(buf);
+
+        if (getuid() != 0) {
+            ovs_fatal(0, "can only chroot as root");
+        }
+
+        if (getpwnam_r(chroot_user, pwdptr, buf, buflen, &tempPwdPtr) != 0) {
+            ovs_fatal(0, "user does not exist");
+        }
+
+        pid = fork();
+        if (pid == 0) {
+            if (chdir(chroot_dir)){
+                ovs_fatal(0, "Cannot change directory");
+            }
+
+            if (chroot("./")){
+                ovs_fatal(0, "Chroot failed");
+            }
+
+            if (setgid(userpwd.pw_gid) != 0) {
+                ovs_fatal(0, "Unable to drop GID");
+            }
+            if (setuid(userpwd.pw_uid) != 0) {
+                ovs_fatal(0, "Unable to drop UID");
+            }
+            if (access("/", W_OK) == 0) {
+                ovs_fatal(0, "We do not want to chroot into a writeable directory");
+            }
+
+            main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting, true);
+            exit(0);
+
+        } else if (pid != -1) {
+
+            /* wait for the forked/chrooted child */
+            while ((exiting == false) && !waitpid(pid, NULL, WNOHANG)) {
+                poll_timer_wait(100);
+                poll_block();
+            };
+
+        } else {
+            ovs_fatal(0, "fork failed");
+        }
+
+    } else {
+        main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting, false);
+    }
+#else
+    main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting, false);
+#endif

     ovsdb_jsonrpc_server_destroy(jsonrpc);
     SHASH_FOR_EACH_SAFE(node, next, &all_dbs) {
@@ -340,6 +418,8 @@ main(int argc, char *argv[])
         }
     }

+    cleanup_entropy();
+
     service_stop();
     return 0;
 }
@@ -1216,7 +1296,8 @@ ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED,

 static void
 parse_options(int *argcp, char **argvp[],
-              struct sset *remotes, char **unixctl_pathp, char **run_command)
+              struct sset *remotes, char **unixctl_pathp, char **run_command,
+              char **chroot_dir, char **chroot_user)
 {
     enum {
         OPT_REMOTE = UCHAR_MAX + 1,
@@ -1225,6 +1306,8 @@ parse_options(int *argcp, char **argvp[],
         OPT_BOOTSTRAP_CA_CERT,
         OPT_ENABLE_DUMMY,
         VLOG_OPTION_ENUMS,
+        OPT_CHROOTDIR,
+        OPT_CHROOTUSER,
         DAEMON_OPTION_ENUMS
     };
     static const struct option long_options[] = {
@@ -1232,6 +1315,8 @@ parse_options(int *argcp, char **argvp[],
         {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
 #ifndef _WIN32
         {"run",         required_argument, NULL, OPT_RUN},
+        {"chroot_dir",   required_argument, NULL, OPT_CHROOTDIR},
+        {"chroot_user",   required_argument, NULL, OPT_CHROOTUSER},
 #endif
         {"help",        no_argument, NULL, 'h'},
         {"version",     no_argument, NULL, 'V'},
@@ -1270,6 +1355,12 @@ parse_options(int *argcp, char **argvp[],
             *run_command = optarg;
             break;

+        case OPT_CHROOTDIR:
+            *chroot_dir = optarg;
+
+        case OPT_CHROOTUSER:
+            *chroot_user = optarg;
+
         case 'h':
             usage();

@@ -1330,6 +1421,8 @@ usage(void)
     vlog_usage();
     printf("\nOther options:\n"
            "  --run COMMAND           run COMMAND as subprocess then exit\n"
+           "  --chrootdir DIRECTORY   chroot into directory\n"
+           "  --chrootuser USER       change user to USER after chroot\n"
            "  --unixctl=SOCKET        override default control socket name\n"
            "  -h, --help              display this help message\n"
            "  -V, --version           display version information\n");

-- 
LSE Leading Security Experts GmbH, Postfach 100121, 64201 Darmstadt
Unternehmenssitz: Weiterstadt, Amtsgericht Darmstadt: HRB8649
Geschäftsführer: Oliver Michel, Sven Walther



More information about the dev mailing list