[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