diff options
Diffstat (limited to 'src/nspawn')
-rw-r--r-- | src/nspawn/nspawn.c | 62 |
1 files changed, 60 insertions, 2 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5a43d5ed12..b59b2673cd 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -22,6 +22,7 @@ #include <signal.h> #include <sched.h> #include <unistd.h> +#include <attr/xattr.h> #include <sys/types.h> #include <sys/syscall.h> #include <sys/mount.h> @@ -921,6 +922,46 @@ static int setup_cgroup(const char *path) { return 0; } +static int save_attributes(const char *cgroup, pid_t pid, const char *uuid, const char *directory) { + char buf[DECIMAL_STR_MAX(pid_t)], path[PATH_MAX]; + int r = 0, k; + + assert(cgroup); + assert(pid >= 0); + assert(arg_directory); + +#ifdef HAVE_XATTR + assert_se(snprintf(buf, sizeof(buf), "%lu", (unsigned long) pid) < (int) sizeof(buf)); + + r = snprintf(path, sizeof(path), "/sys/fs/cgroup/systemd/%s", cgroup); + if (r >= (int) sizeof(path)) { + log_error("cgroup name too long"); + return -EINVAL; + } + + r = setxattr(path, "trusted.init_pid", buf, strlen(buf), XATTR_CREATE); + if (r < 0) + log_warning("Failed to set %s attribute on %s: %m", "trusted.init_pid", path); + + if (uuid) { + k = setxattr(path, "trusted.machine_id", uuid, strlen(uuid), XATTR_CREATE); + if (k < 0) { + log_warning("Failed to set %s attribute on %s: %m", "trusted.machine_id", path); + if (r == 0) + r = k; + } + } + + k = setxattr(path, "trusted.root_directory", directory, strlen(directory), XATTR_CREATE); + if (k < 0) { + log_warning("Failed to set %s attribute on %s: %m", "trusted.machine_id", path); + if (r == 0) + r = k; + } +#endif + return r; +} + static int drop_capabilities(void) { return capability_bounding_set_drop(~arg_retain, false); } @@ -1198,7 +1239,7 @@ int main(int argc, char *argv[]) { arg_directory = get_current_dir_name(); if (!arg_directory) { - log_error("Failed to determine path"); + log_error("Failed to determine path, please use -D."); goto finish; } @@ -1313,13 +1354,19 @@ int main(int argc, char *argv[]) { for (;;) { siginfo_t status; - int pipefd[2]; + int pipefd[2], pipefd2[2]; if (pipe2(pipefd, O_NONBLOCK|O_CLOEXEC) < 0) { log_error("pipe2(): %m"); goto finish; } + if (pipe2(pipefd2, O_NONBLOCK|O_CLOEXEC) < 0) { + log_error("pipe2(): %m"); + close_pipe(pipefd); + goto finish; + } + pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL); if (pid < 0) { if (errno == EINVAL) @@ -1353,6 +1400,7 @@ int main(int argc, char *argv[]) { if (envp[n_env]) n_env ++; + /* Wait for the parent process to log our PID */ close_nointr_nofail(pipefd[1]); fd_wait_for_event(pipefd[0], POLLHUP, -1); close_nointr_nofail(pipefd[0]); @@ -1409,6 +1457,9 @@ int main(int argc, char *argv[]) { if (setup_cgroup(newcg) < 0) goto child_fail; + close_nointr_nofail(pipefd2[1]); + close_nointr_nofail(pipefd2[0]); + /* Mark everything as slave, so that we still * receive mounts from the real root, but don't * propagate mounts to the real root. */ @@ -1617,6 +1668,13 @@ int main(int argc, char *argv[]) { close_nointr_nofail(pipefd[0]); close_nointr_nofail(pipefd[1]); + /* Wait for the child process to establish cgroup hierarchy */ + close_nointr_nofail(pipefd2[1]); + fd_wait_for_event(pipefd2[0], POLLHUP, -1); + close_nointr_nofail(pipefd2[0]); + + save_attributes(newcg, pid, arg_uuid, arg_directory); + fdset_free(fds); fds = NULL; |