chiark / gitweb /
nspawn: bind mount /dev/nul to /proc/kmsg, so that the container can't muck with...
[elogind.git] / src / nspawn.c
index 5a04404587d341e071e89bf2efa11b763ebb77c3..685b4d4e50d4b5c588ebd8374d028b2cb83b046b 100644 (file)
 
 static char *arg_directory = NULL;
 static char *arg_user = NULL;
+static char **arg_controllers = NULL;
 static bool arg_private_network = false;
 
 static int help(void) {
 
         printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
                "Spawn a minimal namespace container for debugging, testing and building.\n\n"
-               "  -h --help            Show this help\n"
-               "  -D --directory=NAME  Root directory for the container\n"
-               "  -u --user=USER       Run the command under specified user or uid\n"
-               "     --private-network Disable network in container\n",
+               "  -h --help             Show this help\n"
+               "  -D --directory=NAME   Root directory for the container\n"
+               "  -u --user=USER        Run the command under specified user or uid\n"
+               "  -C --controllers=LIST Put the container in specified comma-separated cgroup hierarchies\n"
+               "     --private-network  Disable network in container\n",
                program_invocation_short_name);
 
         return 0;
@@ -77,6 +79,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "help",            no_argument,       NULL, 'h'                 },
                 { "directory",       required_argument, NULL, 'D'                 },
                 { "user",            required_argument, NULL, 'u'                 },
+                { "controllers",     required_argument, NULL, 'C'                 },
                 { "private-network", no_argument,       NULL, ARG_PRIVATE_NETWORK },
                 { NULL,              0,                 NULL, 0                   }
         };
@@ -86,7 +89,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:u:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hD:u:C:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -112,6 +115,17 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case 'C':
+                        strv_free(arg_controllers);
+                        arg_controllers = strv_split(optarg, ",");
+                        if (!arg_controllers) {
+                                log_error("Failed to split controllers list.");
+                                return -ENOMEM;
+                        }
+                        strv_uniq(arg_controllers);
+
+                        break;
+
                 case ARG_PRIVATE_NETWORK:
                         arg_private_network = true;
                         break;
@@ -170,7 +184,8 @@ static int mount_all(const char *dest) {
                         break;
                 }
 
-                if ((t = path_is_mount_point(where, false)) < 0) {
+                t = path_is_mount_point(where, false);
+                if (t < 0) {
                         log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t));
                         free(where);
 
@@ -215,6 +230,11 @@ static int mount_all(const char *dest) {
                 free(where);
         }
 
+        if (asprintf(&where, "%s/proc/kmsg", dest) >= 0) {
+                mount("/dev/null", where, "bind", MS_BIND, NULL);
+                free(where);
+        }
+
         return r;
 }
 
@@ -612,6 +632,7 @@ int main(int argc, char *argv[]) {
         pid_t pid = 0;
         int r = EXIT_FAILURE, k;
         char *oldcg = NULL, *newcg = NULL;
+        char **controller = NULL;
         int master = -1;
         const char *console = NULL;
         struct termios saved_attr, raw_attr;
@@ -671,11 +692,18 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if ((k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0)) < 0)  {
+        k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0);
+        if (k < 0)  {
                 log_error("Failed to create cgroup: %s", strerror(-k));
                 goto finish;
         }
 
+        STRV_FOREACH(controller,arg_controllers) {
+                k = cg_create_and_attach(*controller, newcg, 0);
+                if (k < 0)
+                        log_warning("Failed to create cgroup in controller %s: %s", *controller, strerror(-k));
+        }
+
         if ((master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY)) < 0) {
                 log_error("Failed to acquire pseudo tty: %m");
                 goto finish;
@@ -889,6 +917,7 @@ finish:
                 cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, newcg, true);
 
         free(arg_directory);
+        strv_free(arg_controllers);
         free(oldcg);
         free(newcg);