Commit f4364484 by Stéphane Graber

attach: Support unprivileged containers

This change makes lxc-attach and the matching API functions work properly with unprivileged containers. The trick needed to make that possible was to always start with the userns when attaching and also relocate the cgroup management code so that the intermediate process is moved to the cgroup before attaching to the container's namespace as doing so later would fail due to missing permissions. Signed-off-by: 's avatarStéphane Graber <stgraber@ubuntu.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent dbfa7128
...@@ -144,10 +144,10 @@ static int lxc_attach_to_ns(pid_t pid, int which) ...@@ -144,10 +144,10 @@ static int lxc_attach_to_ns(pid_t pid, int which)
* the file for user namepsaces in /proc/$pid/ns will be called * the file for user namepsaces in /proc/$pid/ns will be called
* 'user' once the kernel supports it * 'user' once the kernel supports it
*/ */
static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" }; static char *ns[] = { "user", "mnt", "pid", "uts", "ipc", "net" };
static int flags[] = { static int flags[] = {
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
CLONE_NEWUSER, CLONE_NEWNET CLONE_NEWNET
}; };
static const int size = sizeof(ns) / sizeof(char *); static const int size = sizeof(ns) / sizeof(char *);
int fd[size]; int fd[size];
...@@ -593,7 +593,7 @@ static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_D ...@@ -593,7 +593,7 @@ static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_D
int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process) int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process)
{ {
int ret, status; int ret, status;
pid_t init_pid, pid, attached_pid; pid_t init_pid, pid, attached_pid, expected;
struct lxc_proc_context_info *init_ctx; struct lxc_proc_context_info *init_ctx;
char* cwd; char* cwd;
char* new_cwd; char* new_cwd;
...@@ -689,7 +689,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -689,7 +689,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
if (pid) { if (pid) {
pid_t to_cleanup_pid = pid; pid_t to_cleanup_pid = pid;
int expected = 0;
/* inital thread, we close the socket that is for the /* inital thread, we close the socket that is for the
* subprocesses * subprocesses
...@@ -697,6 +696,44 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -697,6 +696,44 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
close(ipc_sockets[1]); close(ipc_sockets[1]);
free(cwd); free(cwd);
/* attach to cgroup, if requested */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
struct cgroup_meta_data *meta_data;
struct cgroup_process_info *container_info;
meta_data = lxc_cgroup_load_meta();
if (!meta_data) {
ERROR("could not move attached process %ld to cgroup of container", (long)pid);
goto cleanup_error;
}
container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
lxc_cgroup_put_meta(meta_data);
if (!container_info) {
ERROR("could not move attached process %ld to cgroup of container", (long)pid);
goto cleanup_error;
}
/*
* TODO - switch over to using a cgroup_operation. We can't use
* cgroup_enter() as that takes a handler.
*/
ret = lxc_cgroupfs_enter(container_info, pid, false);
lxc_cgroup_process_info_free(container_info);
if (ret < 0) {
ERROR("could not move attached process %ld to cgroup of container", (long)pid);
goto cleanup_error;
}
}
/* Let the child process know to go ahead */
status = 0;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret <= 0) {
ERROR("error using IPC to notify attached process for initialization (0)");
goto cleanup_error;
}
/* get pid from intermediate process */ /* get pid from intermediate process */
ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, sizeof(attached_pid), NULL); ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, sizeof(attached_pid), NULL);
if (ret <= 0) { if (ret <= 0) {
...@@ -730,36 +767,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -730,36 +767,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
goto cleanup_error; goto cleanup_error;
} }
/* attach to cgroup, if requested */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
struct cgroup_meta_data *meta_data;
struct cgroup_process_info *container_info;
meta_data = lxc_cgroup_load_meta();
if (!meta_data) {
ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
goto cleanup_error;
}
container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
lxc_cgroup_put_meta(meta_data);
if (!container_info) {
ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
goto cleanup_error;
}
/*
* TODO - switch over to using a cgroup_operation. We can't use
* cgroup_enter() as that takes a handler.
*/
ret = lxc_cgroupfs_enter(container_info, attached_pid, false);
lxc_cgroup_process_info_free(container_info);
if (ret < 0) {
ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
goto cleanup_error;
}
}
/* tell attached process we're done */ /* tell attached process we're done */
status = 2; status = 2;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status)); ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
...@@ -798,6 +805,16 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -798,6 +805,16 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
*/ */
close(ipc_sockets[0]); close(ipc_sockets[0]);
/* Wait for the parent to have setup cgroups */
expected = 0;
status = -1;
ret = lxc_read_nointr_expect(ipc_sockets[1], &status, sizeof(status), &expected);
if (ret <= 0) {
ERROR("error communicating with child process");
shutdown(ipc_sockets[1], SHUT_RDWR);
rexit(-1);
}
/* attach now, create another subprocess later, since pid namespaces /* attach now, create another subprocess later, since pid namespaces
* only really affect the children of the current process * only really affect the children of the current process
*/ */
......
...@@ -188,11 +188,6 @@ int main(int argc, char *argv[]) ...@@ -188,11 +188,6 @@ int main(int argc, char *argv[])
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
lxc_attach_command_t command; lxc_attach_command_t command;
if (geteuid() != 0) {
ERROR("lxc-attach is not currently supported with unprivileged containers");
return -1;
}
ret = lxc_caps_init(); ret = lxc_caps_init();
if (ret) if (ret)
return ret; return ret;
......
...@@ -2567,11 +2567,6 @@ static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_functio ...@@ -2567,11 +2567,6 @@ static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_functio
if (!c) if (!c)
return -1; return -1;
if (am_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
return -1;
}
return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process); return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
} }
...@@ -2584,11 +2579,6 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t ...@@ -2584,11 +2579,6 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t
if (!c) if (!c)
return -1; return -1;
if (am_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
return -1;
}
command.program = (char*)program; command.program = (char*)program;
command.argv = (char**)argv; command.argv = (char**)argv;
r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid); r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &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