attach: reduce delta

parent 8024504d
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "lsm/lsm.h" #include "lsm/lsm.h"
#include "lxclock.h" #include "lxclock.h"
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "mainloop.h"
#include "namespace.h" #include "namespace.h"
#include "utils.h" #include "utils.h"
...@@ -77,6 +78,8 @@ ...@@ -77,6 +78,8 @@
#define MS_SLAVE (1 << 19) #define MS_SLAVE (1 << 19)
#endif #endif
#define LXC_ATTACH_ALLOCATE_PTY 0x00000000
lxc_log_define(lxc_attach, lxc); lxc_log_define(lxc_attach, lxc);
/* /proc/pid-to-str/current\0 = (5 + 21 + 7 + 1) */ /* /proc/pid-to-str/current\0 = (5 + 21 + 7 + 1) */
...@@ -780,12 +783,30 @@ static signed long get_personality(const char *name, const char *lxcpath) ...@@ -780,12 +783,30 @@ static signed long get_personality(const char *name, const char *lxcpath)
struct attach_clone_payload { struct attach_clone_payload {
int ipc_socket; int ipc_socket;
int pty_fd;
lxc_attach_options_t *options; lxc_attach_options_t *options;
struct lxc_proc_context_info *init_ctx; struct lxc_proc_context_info *init_ctx;
lxc_attach_exec_t exec_function; lxc_attach_exec_t exec_function;
void *exec_payload; void *exec_payload;
}; };
static void lxc_put_attach_clone_payload(struct attach_clone_payload *p)
{
if (p->ipc_socket >= 0) {
shutdown(p->ipc_socket, SHUT_RDWR);
close(p->ipc_socket);
p->ipc_socket = -EBADF;
}
if (p->pty_fd >= 0) {
close(p->pty_fd);
p->pty_fd = -EBADF;
}
if (p->init_ctx)
lxc_proc_put_context_info(p->init_ctx);
}
static int attach_child_main(struct attach_clone_payload *payload) static int attach_child_main(struct attach_clone_payload *payload)
{ {
int fd, lsm_fd, ret; int fd, lsm_fd, ret;
...@@ -913,7 +934,8 @@ static int attach_child_main(struct attach_clone_payload *payload) ...@@ -913,7 +934,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
} }
shutdown(payload->ipc_socket, SHUT_RDWR); shutdown(payload->ipc_socket, SHUT_RDWR);
close(payload->ipc_socket); close(payload->ipc_socket);
payload->ipc_socket = -1; payload->ipc_socket = -EBADF;
lxc_proc_put_context_info(init_ctx);
/* The following is done after the communication socket is shut down. /* The following is done after the communication socket is shut down.
* That way, all errors that might (though unlikely) occur up until this * That way, all errors that might (though unlikely) occur up until this
...@@ -963,19 +985,107 @@ static int attach_child_main(struct attach_clone_payload *payload) ...@@ -963,19 +985,107 @@ static int attach_child_main(struct attach_clone_payload *payload)
} }
} }
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
ret = lxc_login_pty(payload->pty_fd);
if (ret < 0) {
SYSERROR("Failed to prepare pty file descriptor %d", payload->pty_fd);
goto on_error;
}
TRACE("Prepared pty file descriptor %d", payload->pty_fd);
}
/* We're done, so we can now do whatever the user intended us to do. */ /* We're done, so we can now do whatever the user intended us to do. */
rexit(payload->exec_function(payload->exec_payload)); rexit(payload->exec_function(payload->exec_payload));
on_error: on_error:
if (payload->ipc_socket >= 0) { lxc_put_attach_clone_payload(payload);
shutdown(payload->ipc_socket, SHUT_RDWR);
close(payload->ipc_socket);
payload->ipc_socket = -1;
}
lxc_proc_put_context_info(init_ctx);
rexit(EXIT_FAILURE); rexit(EXIT_FAILURE);
} }
static int lxc_attach_pty(struct lxc_conf *conf, struct lxc_console *pty)
{
int ret;
lxc_pty_init(pty);
ret = lxc_pty_create(pty);
if (ret < 0) {
SYSERROR("Failed to create pty");
return -1;
}
/* Shift ttys to container. */
ret = lxc_pty_map_ids(conf, pty);
if (ret < 0) {
ERROR("Failed to shift pty");
goto on_error;
}
return 0;
on_error:
lxc_console_delete(pty);
lxc_pty_conf_free(pty);
return -1;
}
static int lxc_attach_pty_mainloop_init(struct lxc_console *pty,
struct lxc_epoll_descr *descr)
{
int ret;
ret = lxc_mainloop_open(descr);
if (ret < 0) {
ERROR("Failed to create mainloop");
return -1;
}
ret = lxc_console_mainloop_add(descr, pty);
if (ret < 0) {
ERROR("Failed to add handlers to mainloop");
lxc_mainloop_close(descr);
return -1;
}
return 0;
}
static inline void lxc_attach_pty_close_master(struct lxc_console *pty)
{
if (pty->master < 0)
return;
close(pty->master);
pty->master = -EBADF;
}
static inline void lxc_attach_pty_close_slave(struct lxc_console *pty)
{
if (pty->slave < 0)
return;
close(pty->slave);
pty->slave = -EBADF;
}
static inline void lxc_attach_pty_close_peer(struct lxc_console *pty)
{
if (pty->peer < 0)
return;
close(pty->peer);
pty->peer = -EBADF;
}
static inline void lxc_attach_pty_close_log(struct lxc_console *pty)
{
if (pty->log_fd < 0)
return;
close(pty->log_fd);
pty->log_fd = -EBADF;
}
int lxc_attach(const char *name, const char *lxcpath, int lxc_attach(const char *name, const char *lxcpath,
lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_exec_t exec_function, void *exec_payload,
lxc_attach_options_t *options, pid_t *attached_process) lxc_attach_options_t *options, pid_t *attached_process)
...@@ -984,8 +1094,9 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -984,8 +1094,9 @@ int lxc_attach(const char *name, const char *lxcpath,
int ipc_sockets[2]; int ipc_sockets[2];
char *cwd, *new_cwd; char *cwd, *new_cwd;
signed long personality; signed long personality;
pid_t attached_pid, expected, init_pid, pid; pid_t attached_pid, init_pid, pid;
struct lxc_proc_context_info *init_ctx; struct lxc_proc_context_info *init_ctx;
struct lxc_console pty;
struct attach_clone_payload payload = {0}; struct attach_clone_payload payload = {0};
ret = access("/proc/self/ns", X_OK); ret = access("/proc/self/ns", X_OK);
...@@ -1099,6 +1210,18 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1099,6 +1210,18 @@ int lxc_attach(const char *name, const char *lxcpath,
return -1; return -1;
} }
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
ret = lxc_attach_pty(init_ctx->container->lxc_conf, &pty);
if (ret < 0) {
ERROR("Failed to allocate pty");
free(cwd);
lxc_proc_put_context_info(init_ctx);
return -1;
}
} else {
lxc_pty_init(&pty);
}
/* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order /* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
* to make sure we don't irritate other threads that want to fork+exec * to make sure we don't irritate other threads that want to fork+exec
* away * away
...@@ -1159,13 +1282,16 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1159,13 +1282,16 @@ int lxc_attach(const char *name, const char *lxcpath,
} }
if (pid) { if (pid) {
int ret_parent = -1;
pid_t to_cleanup_pid = pid; pid_t to_cleanup_pid = pid;
struct lxc_epoll_descr descr = {0};
/* Initial thread, we close the socket that is for the /* close unneeded file descriptors */
* subprocesses.
*/
close(ipc_sockets[1]); close(ipc_sockets[1]);
free(cwd); free(cwd);
lxc_proc_close_ns_fd(init_ctx);
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
lxc_attach_pty_close_slave(&pty);
/* Attach to cgroup, if requested. */ /* Attach to cgroup, if requested. */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) { if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
...@@ -1175,17 +1301,24 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1175,17 +1301,24 @@ int lxc_attach(const char *name, const char *lxcpath,
"cgroups", pid); "cgroups", pid);
} }
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
ret = lxc_attach_pty_mainloop_init(&pty, &descr);
if (ret < 0)
goto on_error;
TRACE("Initalized pty mainloop");
}
/* Let the child process know to go ahead. */ /* Let the child process know to go ahead. */
status = 0; status = 0;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status)); ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret != sizeof(status)) if (ret != sizeof(status))
goto on_error; goto close_mainloop;
TRACE("Told intermediate process to start initializing"); TRACE("Told intermediate process to start initializing");
/* Get pid of attached process from intermediate process. */ /* Get pid of attached process from intermediate process. */
ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid)); ret = lxc_read_nointr(ipc_sockets[0], &attached_pid, sizeof(attached_pid));
if (ret != sizeof(attached_pid)) if (ret != sizeof(attached_pid))
goto on_error; goto close_mainloop;
TRACE("Received pid %d of attached process in parent pid namespace", attached_pid); TRACE("Received pid %d of attached process in parent pid namespace", attached_pid);
/* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */ /* Ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313. */
...@@ -1197,7 +1330,7 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1197,7 +1330,7 @@ int lxc_attach(const char *name, const char *lxcpath,
/* Reap intermediate process. */ /* Reap intermediate process. */
ret = wait_for_pid(pid); ret = wait_for_pid(pid);
if (ret < 0) if (ret < 0)
goto on_error; goto close_mainloop;
TRACE("Intermediate process %d exited", pid); TRACE("Intermediate process %d exited", pid);
/* We will always have to reap the attached process now. */ /* We will always have to reap the attached process now. */
...@@ -1213,7 +1346,7 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1213,7 +1346,7 @@ int lxc_attach(const char *name, const char *lxcpath,
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
labelfd = lsm_open(attached_pid, on_exec); labelfd = lsm_open(attached_pid, on_exec);
if (labelfd < 0) if (labelfd < 0)
goto on_error; goto close_mainloop;
TRACE("Opened LSM label file descriptor %d", labelfd); TRACE("Opened LSM label file descriptor %d", labelfd);
/* Send child fd of the LSM security module to write to. */ /* Send child fd of the LSM security module to write to. */
...@@ -1221,45 +1354,66 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1221,45 +1354,66 @@ int lxc_attach(const char *name, const char *lxcpath,
close(labelfd); close(labelfd);
if (ret <= 0) { if (ret <= 0) {
SYSERROR("%d", (int)ret); SYSERROR("%d", (int)ret);
goto on_error; goto close_mainloop;
} }
TRACE("Sent LSM label file descriptor %d to child", labelfd); TRACE("Sent LSM label file descriptor %d to child", labelfd);
} }
/* Now shut down communication with child, we're done. */
shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]);
lxc_proc_put_context_info(init_ctx);
/* We're done, the child process should now execute whatever it /* We're done, the child process should now execute whatever it
* is that the user requested. The parent can now track it with * is that the user requested. The parent can now track it with
* waitpid() or similar. * waitpid() or similar.
*/ */
*attached_process = attached_pid; *attached_process = attached_pid;
return 0;
on_error: /* Now shut down communication with child, we're done. */
/* First shut down the socket, then wait for the pid, otherwise
* the pid we're waiting for may never exit.
*/
shutdown(ipc_sockets[0], SHUT_RDWR); shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]); close(ipc_sockets[0]);
if (to_cleanup_pid) ipc_sockets[0] = -1;
ret_parent = 0;
to_cleanup_pid = -1;
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
ret = lxc_mainloop(&descr, -1);
if (ret < 0) {
ret_parent = -1;
to_cleanup_pid = attached_pid;
}
}
close_mainloop:
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
lxc_mainloop_close(&descr);
on_error:
if (ipc_sockets[0] >= 0) {
shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]);
}
if (to_cleanup_pid > 0)
(void)wait_for_pid(to_cleanup_pid); (void)wait_for_pid(to_cleanup_pid);
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
lxc_console_delete(&pty);
lxc_pty_conf_free(&pty);
}
lxc_proc_put_context_info(init_ctx); lxc_proc_put_context_info(init_ctx);
return -1; return ret_parent;
} }
/* First subprocess begins here, we close the socket that is for the /* close unneeded file descriptors */
* initial thread.
*/
close(ipc_sockets[0]); close(ipc_sockets[0]);
ipc_sockets[0] = -EBADF;
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
lxc_attach_pty_close_master(&pty);
lxc_attach_pty_close_peer(&pty);
lxc_attach_pty_close_log(&pty);
}
/* Wait for the parent to have setup cgroups. */ /* Wait for the parent to have setup cgroups. */
expected = 0;
ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status)); ret = lxc_read_nointr(ipc_sockets[1], &status, sizeof(status));
if (ret != sizeof(status) || status != expected) { if (ret != sizeof(status)) {
shutdown(ipc_sockets[1], SHUT_RDWR); shutdown(ipc_sockets[1], SHUT_RDWR);
lxc_proc_put_context_info(init_ctx); lxc_proc_put_context_info(init_ctx);
rexit(-1); rexit(-1);
...@@ -1295,6 +1449,7 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1295,6 +1449,7 @@ int lxc_attach(const char *name, const char *lxcpath,
payload.ipc_socket = ipc_sockets[1]; payload.ipc_socket = ipc_sockets[1];
payload.options = options; payload.options = options;
payload.init_ctx = init_ctx; payload.init_ctx = init_ctx;
payload.pty_fd = pty.slave;
payload.exec_function = exec_function; payload.exec_function = exec_function;
payload.exec_payload = exec_payload; payload.exec_payload = exec_payload;
...@@ -1312,6 +1467,8 @@ int lxc_attach(const char *name, const char *lxcpath, ...@@ -1312,6 +1467,8 @@ int lxc_attach(const char *name, const char *lxcpath,
ERROR("Failed to exec"); ERROR("Failed to exec");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
lxc_attach_pty_close_slave(&pty);
/* Tell grandparent the pid of the pid of the newly created child. */ /* Tell grandparent the pid of the pid of the newly created child. */
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid)); ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment