chiark / gitweb /
nspawn: introduce --capability=all for retaining all capabilities
[elogind.git] / src / nspawn / nspawn.c
index 0a81f972989305cd6610b9103c3ee2eeb7c37c28..0b25334fe9eab93444502fcc07c4d35f5e15c5c8 100644 (file)
@@ -120,6 +120,7 @@ static char **arg_setenv = NULL;
 static bool arg_quiet = false;
 static bool arg_share_system = false;
 static bool arg_register = true;
+static bool arg_keep_unit = false;
 
 static int help(void) {
 
@@ -152,6 +153,8 @@ static int help(void) {
                "     --bind-ro=PATH[:PATH]  Similar, but creates a read-only bind mount\n"
                "     --setenv=NAME=VALUE    Pass an environment variable to PID 1\n"
                "     --register=BOOLEAN     Register container as machine\n"
+               "     --keep-unit            Do not register a scope for the machine, reuse\n"
+               "                            the service unit nspawn is running in\n"
                "  -q --quiet                Do not show status information\n",
                program_invocation_short_name);
 
@@ -172,7 +175,8 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_BIND_RO,
                 ARG_SETENV,
                 ARG_SHARE_SYSTEM,
-                ARG_REGISTER
+                ARG_REGISTER,
+                ARG_KEEP_UNIT
         };
 
         static const struct option options[] = {
@@ -197,6 +201,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "quiet",                 no_argument,       NULL, 'q'                 },
                 { "share-system",          no_argument,       NULL, ARG_SHARE_SYSTEM    },
                 { "register",              required_argument, NULL, ARG_REGISTER        },
+                { "keep-unit",             no_argument,       NULL, ARG_KEEP_UNIT       },
                 {}
         };
 
@@ -295,25 +300,29 @@ static int parse_argv(int argc, char *argv[]) {
                         size_t length;
 
                         FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
+                                _cleanup_free_ char *t;
                                 cap_value_t cap;
-                                char *t;
 
                                 t = strndup(word, length);
                                 if (!t)
                                         return log_oom();
 
-                                if (cap_from_name(t, &cap) < 0) {
-                                        log_error("Failed to parse capability %s.", t);
-                                        free(t);
-                                        return -EINVAL;
+                                if (streq(t, "all")) {
+                                        if (c == ARG_CAPABILITY)
+                                                arg_retain = (uint64_t) -1;
+                                        else
+                                                arg_retain = 0;
+                                } else {
+                                        if (cap_from_name(t, &cap) < 0) {
+                                                log_error("Failed to parse capability %s.", t);
+                                                return -EINVAL;
+                                        }
+
+                                        if (c == ARG_CAPABILITY)
+                                                arg_retain |= 1ULL << (uint64_t) cap;
+                                        else
+                                                arg_retain &= ~(1ULL << (uint64_t) cap);
                                 }
-
-                                free(t);
-
-                                if (c == ARG_CAPABILITY)
-                                        arg_retain |= 1ULL << (uint64_t) cap;
-                                else
-                                        arg_retain &= ~(1ULL << (uint64_t) cap);
                         }
 
                         break;
@@ -410,6 +419,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_register = r;
                         break;
 
+                case ARG_KEEP_UNIT:
+                        arg_keep_unit = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -426,6 +439,11 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
+        if (arg_keep_unit && cg_pid_get_owner_uid(0, NULL) >= 0) {
+                log_error("--keep-unit may not be used when invoked from a user session.");
+                return -EINVAL;
+        }
+
         return 1;
 }
 
@@ -1086,22 +1104,41 @@ static int register_machine(pid_t pid) {
                 return r;
         }
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "CreateMachine",
-                        &error,
-                        NULL,
-                        "sayssusa(sv)",
-                        arg_machine,
-                        SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
-                        "nspawn",
-                        "container",
-                        (uint32_t) pid,
-                        strempty(arg_directory),
-                        !isempty(arg_slice), "Slice", "s", arg_slice);
+        if (arg_keep_unit) {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.machine1",
+                                "/org/freedesktop/machine1",
+                                "org.freedesktop.machine1.Manager",
+                                "RegisterMachine",
+                                &error,
+                                NULL,
+                                "sayssus",
+                                arg_machine,
+                                SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
+                                "nspawn",
+                                "container",
+                                (uint32_t) pid,
+                                strempty(arg_directory));
+        } else {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.machine1",
+                                "/org/freedesktop/machine1",
+                                "org.freedesktop.machine1.Manager",
+                                "CreateMachine",
+                                &error,
+                                NULL,
+                                "sayssusa(sv)",
+                                arg_machine,
+                                SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
+                                "nspawn",
+                                "container",
+                                (uint32_t) pid,
+                                strempty(arg_directory),
+                                !isempty(arg_slice), "Slice", "s", arg_slice);
+        }
+
         if (r < 0) {
                 log_error("Failed to register machine: %s", bus_error_message(&error, r));
                 return r;
@@ -1165,15 +1202,37 @@ static int terminate_machine(pid_t pid) {
         return 0;
 }
 
-static bool audit_enabled(void) {
-        int fd;
+static int reset_audit_loginuid(void) {
+        _cleanup_free_ char *p = NULL;
+        int r;
 
-        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
-        if (fd >= 0) {
-                close_nointr_nofail(fd);
-                return true;
+        if (arg_share_system)
+                return 0;
+
+        r = read_one_line_file("/proc/self/loginuid", &p);
+        if (r == -EEXIST)
+                return 0;
+        if (r < 0) {
+                log_error("Failed to read /proc/self/loginuid: %s", strerror(-r));
+                return r;
         }
-        return false;
+
+        /* Already reset? */
+        if (streq(p, "4294967295"))
+                return 0;
+
+        r = write_string_file("/proc/self/loginuid", "4294967295");
+        if (r < 0) {
+                log_error("Failed to reset audit login UID. This probably means that your kernel is too\n"
+                          "old and you have audit enabled. Note that the auditing subsystem is known to\n"
+                          "be incompatible with containers on old kernels. Please make sure to upgrade\n"
+                          "your kernel or to off auditing with 'audit=0' on the kernel command line before\n"
+                          "using systemd-nspawn. Sleeping for 5s... (%s)\n", strerror(-r));
+
+                sleep(5);
+        }
+
+        return 0;
 }
 
 int main(int argc, char *argv[]) {
@@ -1238,13 +1297,6 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_boot && audit_enabled()) {
-                log_warning("The kernel auditing subsystem is known to be incompatible with containers.\n"
-                            "Please make sure to turn off auditing with 'audit=0' on the kernel command\n"
-                            "line before using systemd-nspawn. Sleeping for 5s...\n");
-                sleep(5);
-        }
-
         if (path_equal(arg_directory, "/")) {
                 log_error("Spawning container on root directory not supported.");
                 goto finish;
@@ -1403,6 +1455,9 @@ int main(int argc, char *argv[]) {
                                 goto child_fail;
                         }
 
+                        if (reset_audit_loginuid() < 0)
+                                goto child_fail;
+
                         if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) {
                                 log_error("PR_SET_PDEATHSIG failed: %m");
                                 goto child_fail;