struct lxc_conf *conf;
char *name, *lxcpath;
struct attach_clone_payload payload = {0};
+ int ret_parent = -1;
+ pid_t to_cleanup_pid;
+ struct lxc_epoll_descr descr = {0};
ret = access("/proc/self/ns", X_OK);
if (ret)
return -1;
}
- if (pid) {
- int ret_parent = -1;
- pid_t to_cleanup_pid = pid;
- struct lxc_epoll_descr descr = {0};
-
+ if (pid == 0) {
/* close unneeded file descriptors */
- close(ipc_sockets[1]);
- free(cwd);
- lxc_proc_close_ns_fd(init_ctx);
- if (options->attach_flags & LXC_ATTACH_TERMINAL)
- lxc_attach_terminal_close_pts(&terminal);
-
- /* Attach to cgroup, if requested. */
- if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
- /*
- * If this is the unified hierarchy cgroup_attach() is
- * enough.
- */
- ret = cgroup_attach(conf, name, lxcpath, pid);
- if (ret) {
- call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
-
- cgroup_ops = cgroup_init(conf);
- if (!cgroup_ops)
- goto on_error;
+ close_prot_errno_disarm(ipc_sockets[0]);
- if (!cgroup_ops->attach(cgroup_ops, conf, name, lxcpath, pid))
- goto on_error;
- }
- TRACE("Moved intermediate process %d into container's cgroups", pid);
+ if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+ lxc_attach_terminal_close_ptx(&terminal);
+ lxc_attach_terminal_close_peer(&terminal);
+ lxc_attach_terminal_close_log(&terminal);
}
- /* Setup /proc limits */
- if (!lxc_list_empty(&conf->procs)) {
- ret = setup_proc_filesystem(&conf->procs, pid);
- if (ret < 0)
- goto on_error;
+ /* Wait for the parent to have setup cgroups. */
+ ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status));
+ if (ret != sizeof(status)) {
+ shutdown(ipc_sockets[1], SHUT_RDWR);
+ lxc_proc_put_context_info(init_ctx);
+ _exit(EXIT_FAILURE);
}
- /* Setup resource limits */
- if (!lxc_list_empty(&conf->limits)) {
- ret = setup_resource_limits(&conf->limits, pid);
- if (ret < 0)
- goto on_error;
+ TRACE("Intermediate process starting to initialize");
+
+ /* Attach now, create another subprocess later, since pid namespaces
+ * only really affect the children of the current process.
+ */
+ ret = lxc_attach_to_ns(init_pid, init_ctx);
+ if (ret < 0) {
+ ERROR("Failed to enter namespaces");
+ shutdown(ipc_sockets[1], SHUT_RDWR);
+ lxc_proc_put_context_info(init_ctx);
+ _exit(EXIT_FAILURE);
}
- if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
- if (ret < 0)
- goto on_error;
+ /* close namespace file descriptors */
+ lxc_proc_close_ns_fd(init_ctx);
- TRACE("Initialized terminal mainloop");
+ /* Attach succeeded, try to cwd. */
+ if (options->initial_cwd)
+ new_cwd = options->initial_cwd;
+ else
+ new_cwd = cwd;
+ if (new_cwd) {
+ ret = chdir(new_cwd);
+ if (ret < 0)
+ WARN("Could not change directory to \"%s\"", new_cwd);
}
+ free(cwd);
- /* Let the child process know to go ahead. */
- status = 0;
- ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
- if (ret != sizeof(status))
- goto close_mainloop;
-
- TRACE("Told intermediate process to start initializing");
+ /* Create attached process. */
+ payload.ipc_socket = ipc_sockets[1];
+ payload.options = options;
+ payload.init_ctx = init_ctx;
+ payload.terminal_pts_fd = terminal.pty;
+ payload.exec_function = exec_function;
+ payload.exec_payload = exec_payload;
+
+ pid = lxc_raw_clone(CLONE_PARENT, NULL);
+ if (pid < 0) {
+ SYSERROR("Failed to clone attached process");
+ shutdown(ipc_sockets[1], SHUT_RDWR);
+ lxc_proc_put_context_info(init_ctx);
+ _exit(EXIT_FAILURE);
+ }
- /* Get pid of attached process from intermediate process. */
- ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid));
- if (ret != sizeof(attached_pid))
- goto close_mainloop;
+ if (pid == 0) {
+ if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+ ret = lxc_terminal_signal_sigmask_safe_blocked(&terminal);
+ if (ret < 0) {
+ SYSERROR("Failed to reset signal mask");
+ _exit(EXIT_FAILURE);
+ }
+ }
- TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
+ ret = attach_child_main(&payload);
+ if (ret < 0)
+ ERROR("Failed to exec");
- /* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
- if (options->stdin_fd == 0) {
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
+ _exit(EXIT_FAILURE);
}
- /* Reap intermediate process. */
- ret = wait_for_pid(pid);
- if (ret < 0)
- goto close_mainloop;
+ if (options->attach_flags & LXC_ATTACH_TERMINAL)
+ lxc_attach_terminal_close_pts(&terminal);
- TRACE("Intermediate process %d exited", pid);
+ /* Tell grandparent the pid of the pid of the newly created child. */
+ ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
+ if (ret != sizeof(pid)) {
+ /* If this really happens here, this is very unfortunate, since
+ * the parent will not know the pid of the attached process and
+ * will not be able to wait for it (and we won't either due to
+ * CLONE_PARENT) so the parent won't be able to reap it and the
+ * attached process will remain a zombie.
+ */
+ shutdown(ipc_sockets[1], SHUT_RDWR);
+ lxc_proc_put_context_info(init_ctx);
+ _exit(EXIT_FAILURE);
+ }
- /* We will always have to reap the attached process now. */
- to_cleanup_pid = attached_pid;
+ TRACE("Sending pid %d of attached process", pid);
- /* Open LSM fd and send it to child. */
- if ((options->namespaces & CLONE_NEWNS) &&
- (options->attach_flags & LXC_ATTACH_LSM) &&
- init_ctx->lsm_label) {
- int labelfd;
- bool on_exec;
+ /* The rest is in the hands of the initial and the attached process. */
+ lxc_proc_put_context_info(init_ctx);
+ _exit(EXIT_SUCCESS);
+ }
- ret = -1;
- on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
- labelfd = init_ctx->lsm_ops->process_label_fd_get(init_ctx->lsm_ops,
- attached_pid, on_exec);
- if (labelfd < 0)
- goto close_mainloop;
+ to_cleanup_pid = pid;
- TRACE("Opened LSM label file descriptor %d", labelfd);
+ /* close unneeded file descriptors */
+ close(ipc_sockets[1]);
+ free(cwd);
+ lxc_proc_close_ns_fd(init_ctx);
+ if (options->attach_flags & LXC_ATTACH_TERMINAL)
+ lxc_attach_terminal_close_pts(&terminal);
- /* Send child fd of the LSM security module to write to. */
- ret = lxc_abstract_unix_send_fds(ipc_sockets[0], &labelfd, 1, NULL, 0);
- if (ret <= 0) {
- if (ret < 0)
- SYSERROR("Failed to send lsm label fd");
+ /* Attach to cgroup, if requested. */
+ if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
+ /*
+ * If this is the unified hierarchy cgroup_attach() is
+ * enough.
+ */
+ ret = cgroup_attach(conf, name, lxcpath, pid);
+ if (ret) {
+ call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
- close(labelfd);
- goto close_mainloop;
- }
+ cgroup_ops = cgroup_init(conf);
+ if (!cgroup_ops)
+ goto on_error;
- close(labelfd);
- TRACE("Sent LSM label file descriptor %d to child", labelfd);
+ if (!cgroup_ops->attach(cgroup_ops, conf, name, lxcpath, pid))
+ goto on_error;
}
+ TRACE("Moved intermediate process %d into container's cgroups", pid);
+ }
- if (conf->seccomp.seccomp) {
- ret = lxc_seccomp_recv_notifier_fd(&conf->seccomp, ipc_sockets[0]);
- if (ret < 0)
- goto close_mainloop;
+ /* Setup /proc limits */
+ if (!lxc_list_empty(&conf->procs)) {
+ ret = setup_proc_filesystem(&conf->procs, pid);
+ if (ret < 0)
+ goto on_error;
+ }
- ret = lxc_seccomp_add_notifier(name, lxcpath, &conf->seccomp);
- if (ret < 0)
- goto close_mainloop;
- }
+ /* Setup resource limits */
+ if (!lxc_list_empty(&conf->limits)) {
+ ret = setup_resource_limits(&conf->limits, pid);
+ if (ret < 0)
+ goto on_error;
+ }
- /* We're done, the child process should now execute whatever it
- * is that the user requested. The parent can now track it with
- * waitpid() or similar.
- */
+ if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+ ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
+ if (ret < 0)
+ goto on_error;
- *attached_process = attached_pid;
+ TRACE("Initialized terminal mainloop");
+ }
- /* Now shut down communication with child, we're done. */
- shutdown(ipc_sockets[0], SHUT_RDWR);
- close(ipc_sockets[0]);
- ipc_sockets[0] = -1;
+ /* Let the child process know to go ahead. */
+ status = 0;
+ ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
+ if (ret != sizeof(status))
+ goto close_mainloop;
- ret_parent = 0;
- to_cleanup_pid = -1;
+ TRACE("Told intermediate process to start initializing");
- if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- ret = lxc_mainloop(&descr, -1);
- if (ret < 0) {
- ret_parent = -1;
- to_cleanup_pid = attached_pid;
- }
- }
+ /* Get pid of attached process from intermediate process. */
+ ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid));
+ if (ret != sizeof(attached_pid))
+ goto close_mainloop;
- close_mainloop:
- if (options->attach_flags & LXC_ATTACH_TERMINAL)
- lxc_mainloop_close(&descr);
+ TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
- on_error:
- if (ipc_sockets[0] >= 0) {
- shutdown(ipc_sockets[0], SHUT_RDWR);
- close(ipc_sockets[0]);
- }
+ /* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
+ if (options->stdin_fd == 0) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ }
- if (to_cleanup_pid > 0)
- (void)wait_for_pid(to_cleanup_pid);
+ /* Reap intermediate process. */
+ ret = wait_for_pid(pid);
+ if (ret < 0)
+ goto close_mainloop;
- if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- lxc_terminal_delete(&terminal);
- lxc_terminal_conf_free(&terminal);
- }
+ TRACE("Intermediate process %d exited", pid);
- lxc_proc_put_context_info(init_ctx);
- return ret_parent;
- }
+ /* We will always have to reap the attached process now. */
+ to_cleanup_pid = attached_pid;
- /* close unneeded file descriptors */
- close_prot_errno_disarm(ipc_sockets[0]);
+ /* Open LSM fd and send it to child. */
+ if ((options->namespaces & CLONE_NEWNS) &&
+ (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
+ int labelfd;
+ bool on_exec;
- if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- lxc_attach_terminal_close_ptx(&terminal);
- lxc_attach_terminal_close_peer(&terminal);
- lxc_attach_terminal_close_log(&terminal);
- }
+ ret = -1;
+ on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
+ labelfd = init_ctx->lsm_ops->process_label_fd_get(init_ctx->lsm_ops,
+ attached_pid, on_exec);
+ if (labelfd < 0)
+ goto close_mainloop;
- /* Wait for the parent to have setup cgroups. */
- ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status));
- if (ret != sizeof(status)) {
- shutdown(ipc_sockets[1], SHUT_RDWR);
- lxc_proc_put_context_info(init_ctx);
- _exit(EXIT_FAILURE);
- }
+ TRACE("Opened LSM label file descriptor %d", labelfd);
- TRACE("Intermediate process starting to initialize");
+ /* Send child fd of the LSM security module to write to. */
+ ret = lxc_abstract_unix_send_fds(ipc_sockets[0], &labelfd, 1, NULL, 0);
+ if (ret <= 0) {
+ if (ret < 0)
+ SYSERROR("Failed to send lsm label fd");
- /* Attach now, create another subprocess later, since pid namespaces
- * only really affect the children of the current process.
- */
- ret = lxc_attach_to_ns(init_pid, init_ctx);
- if (ret < 0) {
- ERROR("Failed to enter namespaces");
- shutdown(ipc_sockets[1], SHUT_RDWR);
- lxc_proc_put_context_info(init_ctx);
- _exit(EXIT_FAILURE);
+ close(labelfd);
+ goto close_mainloop;
+ }
+
+ close(labelfd);
+ TRACE("Sent LSM label file descriptor %d to child", labelfd);
}
- /* close namespace file descriptors */
- lxc_proc_close_ns_fd(init_ctx);
+ if (conf->seccomp.seccomp) {
+ ret = lxc_seccomp_recv_notifier_fd(&conf->seccomp, ipc_sockets[0]);
+ if (ret < 0)
+ goto close_mainloop;
- /* Attach succeeded, try to cwd. */
- if (options->initial_cwd)
- new_cwd = options->initial_cwd;
- else
- new_cwd = cwd;
- if (new_cwd) {
- ret = chdir(new_cwd);
+ ret = lxc_seccomp_add_notifier(name, lxcpath, &conf->seccomp);
if (ret < 0)
- WARN("Could not change directory to \"%s\"", new_cwd);
+ goto close_mainloop;
}
- free(cwd);
- /* Create attached process. */
- payload.ipc_socket = ipc_sockets[1];
- payload.options = options;
- payload.init_ctx = init_ctx;
- payload.terminal_pts_fd = terminal.pty;
- payload.exec_function = exec_function;
- payload.exec_payload = exec_payload;
+ /* We're done, the child process should now execute whatever it
+ * is that the user requested. The parent can now track it with
+ * waitpid() or similar.
+ */
- pid = lxc_raw_clone(CLONE_PARENT, NULL);
- if (pid < 0) {
- SYSERROR("Failed to clone attached process");
- shutdown(ipc_sockets[1], SHUT_RDWR);
- lxc_proc_put_context_info(init_ctx);
- _exit(EXIT_FAILURE);
- }
+ *attached_process = attached_pid;
- if (pid == 0) {
- if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- ret = lxc_terminal_signal_sigmask_safe_blocked(&terminal);
- if (ret < 0) {
- SYSERROR("Failed to reset signal mask");
- _exit(EXIT_FAILURE);
- }
- }
+ /* Now shut down communication with child, we're done. */
+ shutdown(ipc_sockets[0], SHUT_RDWR);
+ close(ipc_sockets[0]);
+ ipc_sockets[0] = -1;
- ret = attach_child_main(&payload);
- if (ret < 0)
- ERROR("Failed to exec");
+ ret_parent = 0;
+ to_cleanup_pid = -1;
- _exit(EXIT_FAILURE);
+ if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+ ret = lxc_mainloop(&descr, -1);
+ if (ret < 0) {
+ ret_parent = -1;
+ to_cleanup_pid = attached_pid;
+ }
}
+close_mainloop:
if (options->attach_flags & LXC_ATTACH_TERMINAL)
- lxc_attach_terminal_close_pts(&terminal);
+ lxc_mainloop_close(&descr);
- /* Tell grandparent the pid of the pid of the newly created child. */
- ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
- if (ret != sizeof(pid)) {
- /* If this really happens here, this is very unfortunate, since
- * the parent will not know the pid of the attached process and
- * will not be able to wait for it (and we won't either due to
- * CLONE_PARENT) so the parent won't be able to reap it and the
- * attached process will remain a zombie.
- */
- shutdown(ipc_sockets[1], SHUT_RDWR);
- lxc_proc_put_context_info(init_ctx);
- _exit(EXIT_FAILURE);
+on_error:
+ if (ipc_sockets[0] >= 0) {
+ shutdown(ipc_sockets[0], SHUT_RDWR);
+ close(ipc_sockets[0]);
}
- TRACE("Sending pid %d of attached process", pid);
+ if (to_cleanup_pid > 0)
+ (void)wait_for_pid(to_cleanup_pid);
+
+ if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+ lxc_terminal_delete(&terminal);
+ lxc_terminal_conf_free(&terminal);
+ }
- /* The rest is in the hands of the initial and the attached process. */
lxc_proc_put_context_info(init_ctx);
- _exit(EXIT_SUCCESS);
+ return ret_parent;
}
int lxc_attach_run_command(void *payload)