#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>
int r = 0;
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
- char _cleanup_free_ *where = NULL;
+ _cleanup_free_ char *where = NULL;
int t;
where = strjoin(dest, "/", mount_table[k].where, NULL);
}
static int setup_resolv_conf(const char *dest) {
- char *where;
+ char _cleanup_free_ *where = NULL;
+ _cleanup_close_ int fd = -1;
assert(dest);
if (!where)
return log_oom();
+ fd = open(where, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
+
/* We don't really care for the results of this really. If it
* fails, it fails, but meh... */
- if (mount("/etc/resolv.conf", where, "bind", MS_BIND, NULL) >= 0)
- mount("/etc/resolv.conf", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
-
- free(where);
+ if (mount("/etc/resolv.conf", where, "bind", MS_BIND, NULL) < 0)
+ log_warning("Failed to bind mount /etc/resolv.conf: %m");
+ else
+ if (mount("/etc/resolv.conf", where, "bind",
+ MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+ log_error("Failed to remount /etc/resolv.conf readonly: %m");
+ return -errno;
+ }
return 0;
}
static int setup_boot_id(const char *dest) {
- char _cleanup_free_ *from = NULL, *to = NULL;
+ _cleanup_free_ char *from = NULL, *to = NULL;
sd_id128_t rnd;
char as_uuid[37];
int r;
const char *d;
int r = 0;
- mode_t _cleanup_umask_ u;
+ _cleanup_umask_ mode_t u;
assert(dest);
NULSTR_FOREACH(d, devnodes) {
struct stat st;
- char _cleanup_free_ *from = NULL, *to = NULL;
+ _cleanup_free_ char *from = NULL, *to = NULL;
asprintf(&from, "/dev/%s", d);
asprintf(&to, "%s/dev/%s", dest, d);
static int setup_dev_console(const char *dest, const char *console) {
struct stat st;
- char _cleanup_free_ *to = NULL;
+ _cleanup_free_ char *to = NULL;
int r;
- mode_t _cleanup_umask_ u;
+ _cleanup_umask_ mode_t u;
assert(dest);
assert(console);
}
static int setup_kmsg(const char *dest, int kmsg_socket) {
- char _cleanup_free_ *from = NULL, *to = NULL;
+ _cleanup_free_ char *from = NULL, *to = NULL;
int r, fd, k;
- mode_t _cleanup_umask_ u;
+ _cleanup_umask_ mode_t u;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
static int setup_journal(const char *directory) {
sd_id128_t machine_id;
- char _cleanup_free_ *p = NULL, *b = NULL, *q = NULL, *d = NULL;
+ _cleanup_free_ char *p = NULL, *b = NULL, *q = NULL, *d = NULL;
char *id;
int r;
return 0;
}
-static int drop_capabilities(void) {
- return capability_bounding_set_drop(~arg_retain, false);
-}
+static int save_attributes(const char *cgroup, pid_t pid, const char *uuid, const char *directory) {
+ _cleanup_free_ char *path = NULL;
+ char buf[DECIMAL_STR_MAX(pid_t)];
+ int r = 0, k;
-static int is_os_tree(const char *path) {
- int r;
- char *p;
- /* We use /bin/sh as flag file if something is an OS */
+ assert(cgroup);
+ assert(pid >= 0);
+ assert(arg_directory);
- if (asprintf(&p, "%s/bin/sh", path) < 0)
- return -ENOMEM;
+#ifdef HAVE_XATTR
+ assert_se(snprintf(buf, sizeof(buf), "%lu", (unsigned long) pid) < (int) sizeof(buf));
- r = access(p, F_OK);
- free(p);
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, cgroup, NULL, &path);
+ if (r < 0) {
+ log_error("Failed to get path: %s", strerror(-r));
+ return r;
+ }
+
+ 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;
+ }
+ }
- return r < 0 ? 0 : 1;
+ 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.root_directory", path);
+ if (r == 0)
+ r = k;
+ }
+#endif
+ return r;
+}
+
+static int drop_capabilities(void) {
+ return capability_bounding_set_drop(~arg_retain, false);
}
static int process_pty(int master, pid_t pid, sigset_t *mask) {
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;
}
goto finish;
}
- if (is_os_tree(arg_directory) <= 0) {
+ if (path_is_os_tree(arg_directory) <= 0) {
log_error("Directory %s doesn't look like an OS root directory. Refusing.", arg_directory);
goto finish;
}
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)
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]);
if (setup_cgroup(newcg) < 0)
goto child_fail;
+ close_pipe(pipefd2);
+
/* Mark everything as slave, so that we still
* receive mounts from the real root, but don't
* propagate mounts to the real root. */
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;