Enter existing user namespace if present

When executing an additional process in a container, all namespaces are
entered but the user namespace. As a result, the process may be
executed as the host's root user. This has both functionality and
security implications.

Fix this by adding the missing user namespace to the array of
namespaces. Since joining a user namespace in which the caller is
already a member yields an error, skip namespaces we're already in.

Last, remove a needless and buggy AT_SYMLINK_NOFOLLOW in the code.

Signed-off-by: Ido Yariv <ido@wizery.com>
This commit is contained in:
Ido Yariv 2015-08-08 12:30:55 -04:00
parent 08b5415ffa
commit 08366a8597
1 changed files with 19 additions and 3 deletions

View File

@ -65,11 +65,11 @@ static int clone_parent(jmp_buf * env)
void nsexec() void nsexec()
{ {
char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" }; char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt", "user" };
const int num = sizeof(namespaces) / sizeof(char *); const int num = sizeof(namespaces) / sizeof(char *);
jmp_buf env; jmp_buf env;
char buf[PATH_MAX], *val; char buf[PATH_MAX], *val;
int i, tfd, child, len, pipenum, consolefd = -1; int i, tfd, self_tfd, child, len, pipenum, consolefd = -1;
pid_t pid; pid_t pid;
char *console; char *console;
@ -114,17 +114,30 @@ void nsexec()
exit(1); exit(1);
} }
self_tfd = open("/proc/self/ns", O_DIRECTORY | O_RDONLY);
if (self_tfd == -1) {
pr_perror("Failed to open /proc/self/ns");
exit(1);
}
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
struct stat st; struct stat st;
struct stat self_st;
int fd; int fd;
/* Symlinks on all namespaces exist for dead processes, but they can't be opened */ /* Symlinks on all namespaces exist for dead processes, but they can't be opened */
if (fstatat(tfd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) { if (fstatat(tfd, namespaces[i], &st, 0) == -1) {
// Ignore nonexistent namespaces. // Ignore nonexistent namespaces.
if (errno == ENOENT) if (errno == ENOENT)
continue; continue;
} }
/* Skip namespaces we're already part of */
if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 &&
st.st_ino == self_st.st_ino) {
continue;
}
fd = openat(tfd, namespaces[i], O_RDONLY); fd = openat(tfd, namespaces[i], O_RDONLY);
if (fd == -1) { if (fd == -1) {
pr_perror("Failed to open ns file %s for ns %s", buf, pr_perror("Failed to open ns file %s for ns %s", buf,
@ -139,6 +152,9 @@ void nsexec()
close(fd); close(fd);
} }
close(self_tfd);
close(tfd);
if (setjmp(env) == 1) { if (setjmp(env) == 1) {
// Child // Child