Chromium Code Reviews| Index: sandbox/linux/services/credentials.cc |
| diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc |
| index 803af159704f632102a65c6cea4b962b5d17524f..452c2076c5f19dce5dc4df908d325025a0e74ae4 100644 |
| --- a/sandbox/linux/services/credentials.cc |
| +++ b/sandbox/linux/services/credentials.cc |
| @@ -150,6 +150,18 @@ int CapabilityToKernelValue(Credentials::Capability cap) { |
| return 0; |
| } |
| +void SetGidAndUidMaps(gid_t gid, uid_t uid) { |
| + if (NamespaceUtils::KernelSupportsDenySetgroups()) { |
| + PCHECK(NamespaceUtils::DenySetgroups()); |
| + } |
| + DCHECK(GetRESIds(NULL, NULL)); |
| + const char kGidMapFile[] = "/proc/self/gid_map"; |
| + const char kUidMapFile[] = "/proc/self/uid_map"; |
| + PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid)); |
| + PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid)); |
| + DCHECK(GetRESIds(NULL, NULL)); |
| +} |
| + |
| } // namespace. |
| // static |
| @@ -253,8 +265,14 @@ bool Credentials::CanCreateProcessInNewUserNS() { |
| return false; |
| #endif |
| - // This is roughly a fork(). |
| - const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); |
| + uid_t uid; |
| + gid_t gid; |
| + if (!GetRESIds(&uid, &gid)) { |
| + return false; |
| + } |
| + |
| + const pid_t pid = |
| + base::ForkWithFlags(CLONE_NEWUSER | SIGCHLD, nullptr, nullptr); |
| if (pid == -1) { |
| CheckCloneNewUserErrno(errno); |
| @@ -262,20 +280,30 @@ bool Credentials::CanCreateProcessInNewUserNS() { |
| } |
| // The parent process could have had threads. In the child, these threads |
| - // have disappeared. Make sure to not do anything in the child, as this is a |
| - // fragile execution environment. |
| + // have disappeared. |
| if (pid == 0) { |
| + // unshare() requires the effective uid and gid to have a mapping in the |
| + // parent namespace. |
| + SetGidAndUidMaps(gid, uid); |
| + |
| + // Make sure we drop CAP_SYS_ADMIN. |
| + auto proc_fd = sandbox::ProcUtil::OpenProc(); |
| + CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd.get())); |
|
mdempsky
2017/01/10 22:48:23
nit: You can just use DropAllCapabilities(), which
Tom (Use chromium acct)
2017/01/10 23:32:03
Done.
|
| + |
| + // Ensure we have unprivileged use of CLONE_NEWUSER. Debian |
| + // Jessie explicitly forbids this case. See: |
| + // add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by-default.patch |
| + PCHECK(0 == sys_unshare(CLONE_NEWUSER)); |
| _exit(kExitSuccess); |
| } |
| // Always reap the child. |
| int status = -1; |
| PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); |
| - CHECK(WIFEXITED(status)); |
| - CHECK_EQ(kExitSuccess, WEXITSTATUS(status)); |
| - // clone(2) succeeded, we can use CLONE_NEWUSER. |
| - return true; |
| + // clone(2) succeeded. Now return true only if the system grants |
| + // unprivileged use of CLONE_NEWUSER as well. |
| + return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess; |
| } |
| bool Credentials::MoveToNewUserNS() { |
| @@ -296,18 +324,9 @@ bool Credentials::MoveToNewUserNS() { |
| return false; |
| } |
| - if (NamespaceUtils::KernelSupportsDenySetgroups()) { |
| - PCHECK(NamespaceUtils::DenySetgroups()); |
| - } |
| - |
| // The current {r,e,s}{u,g}id is now an overflow id (c.f. |
| // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. |
| - DCHECK(GetRESIds(NULL, NULL)); |
| - const char kGidMapFile[] = "/proc/self/gid_map"; |
| - const char kUidMapFile[] = "/proc/self/uid_map"; |
| - PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid)); |
| - PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid)); |
| - DCHECK(GetRESIds(NULL, NULL)); |
| + SetGidAndUidMaps(gid, uid); |
| return true; |
| } |