attach: correctly handle namespace inheritance

When attaching to a container's namespaces we did not handle the case where we inherited namespaces correctly. In essence, liblxc on start records the namespaces the container was created with in the handler. But it only records the clone flags that were passed to clone() and doesn't record the namespaces we e.g. inherited from other containers. This means that attach only ever attached to the clone flags. But this is only correct if all other namespaces not recorded in the handler refer to the namespaces of the caller. However, this need not be the case if the container has inherited namespaces from another container. To handle this case we need to check whether caller and container are in the same namespace. If they are, we know that things are all good. If they aren't then we need to attach to these namespaces as well. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent f3d91bf0
...@@ -249,24 +249,89 @@ static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx) ...@@ -249,24 +249,89 @@ static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx)
free(ctx); free(ctx);
} }
/**
* in_same_namespace - Check whether two processes are in the same namespace.
* @pid1 - PID of the first process.
* @pid2 - PID of the second process.
* @ns - Name of the namespace to check. Must correspond to one of the names
* for the namespaces as shown in /proc/<pid/ns/
*
* If the two processes are not in the same namespace returns an fd to the
* namespace of the second process identified by @pid2. If the two processes are
* in the same namespace returns -EINVAL, -1 if an error occurred.
*/
static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
{
int ns_fd1 = -1, ns_fd2 = -1, ret = -1;
struct stat ns_st1, ns_st2;
ns_fd1 = lxc_preserve_ns(pid1, ns);
if (ns_fd1 < 0)
goto out;
ns_fd2 = lxc_preserve_ns(pid2, ns);
if (ns_fd2 < 0)
goto out;
ret = fstat(ns_fd1, &ns_st1);
if (ret < 0)
goto out;
ret = fstat(ns_fd2, &ns_st2);
if (ret < 0)
goto out;
/* processes are in the same namespace */
ret = -EINVAL;
if ((ns_st1.st_dev == ns_st2.st_dev ) && (ns_st1.st_ino == ns_st2.st_ino))
goto out;
/* processes are in different namespaces */
ret = ns_fd2;
ns_fd2 = -1;
out:
if (ns_fd1 >= 0)
close(ns_fd1);
if (ns_fd2 >= 0)
close(ns_fd2);
return ret;
}
static int lxc_attach_to_ns(pid_t pid, int which) static int lxc_attach_to_ns(pid_t pid, int which)
{ {
int fd[LXC_NS_MAX]; int fd[LXC_NS_MAX];
int i, j, saved_errno; int i, j, ret, saved_errno;
if (access("/proc/self/ns", X_OK)) { ret = access("/proc/self/ns", X_OK);
if (ret) {
ERROR("Does this kernel version support namespaces?"); ERROR("Does this kernel version support namespaces?");
return -1; return -1;
} }
for (i = 0; i < LXC_NS_MAX; i++) { for (i = 0; i < LXC_NS_MAX; i++) {
fd[i] = -EINVAL;
/* Ignore if we are not supposed to attach to that namespace. */ /* Ignore if we are not supposed to attach to that namespace. */
if (which != -1 && !(which & ns_info[i].clone_flag)) { if (which != -1 && !(which & ns_info[i].clone_flag)) {
fd[i] = -1; /* We likely inherited the namespace from someone. We
continue; * need to check whether we are already in the same
* namespace. If we are then there's nothing for us to
* do. If we are not then we need to attach to it.
*/
fd[i] = in_same_namespace(getpid(), pid, ns_info[i].proc_name);
/* we are in the same namespace */
if (fd[i] == -EINVAL) {
DEBUG("Inheriting %s namespace from %d",
ns_info[i].proc_name, pid);
continue;
}
} }
fd[i] = lxc_preserve_ns(pid, ns_info[i].proc_name); if (fd[i] == -EINVAL)
fd[i] = lxc_preserve_ns(pid, ns_info[i].proc_name);
if (fd[i] < 0) { if (fd[i] < 0) {
saved_errno = errno; saved_errno = errno;
...@@ -277,8 +342,8 @@ static int lxc_attach_to_ns(pid_t pid, int which) ...@@ -277,8 +342,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
close(fd[j]); close(fd[j]);
errno = saved_errno; errno = saved_errno;
SYSERROR("Failed to open namespace: \"%s\".", SYSERROR("Failed to attach to %s namespace of %d",
ns_info[i].proc_name); ns_info[i].proc_name, pid);
return -1; return -1;
} }
} }
...@@ -294,12 +359,12 @@ static int lxc_attach_to_ns(pid_t pid, int which) ...@@ -294,12 +359,12 @@ static int lxc_attach_to_ns(pid_t pid, int which)
close(fd[j]); close(fd[j]);
errno = saved_errno; errno = saved_errno;
SYSERROR("Failed to attach to namespace \"%s\".", SYSERROR("Failed to attach to %s namespace of %d",
ns_info[i].proc_name); ns_info[i].proc_name, pid);
return -1; return -1;
} }
DEBUG("Attached to namespace \"%s\".", ns_info[i].proc_name); DEBUG("Attached to %s namespace of %d", ns_info[i].proc_name, pid);
close(fd[i]); close(fd[i]);
} }
......
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