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..5561f41f822f62b8eabed6215338b602b2467e72 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,6 +265,12 @@ bool Credentials::CanCreateProcessInNewUserNS() { |
| return false; |
| #endif |
| + uid_t uid; |
| + gid_t gid; |
| + if (!GetRESIds(&uid, &gid)) { |
| + return false; |
| + } |
| + |
| // This is roughly a fork(). |
| const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); |
| @@ -265,17 +283,29 @@ bool Credentials::CanCreateProcessInNewUserNS() { |
| // have disappeared. Make sure to not do anything in the child, as this is a |
| // fragile execution environment. |
| if (pid == 0) { |
| - _exit(kExitSuccess); |
| + // 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())); |
| + |
| + // 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 |
| + int ret = sys_unshare(CLONE_NEWUSER); |
|
mdempsky
2016/12/14 05:11:11
I would probably do:
PCHECK(sys_unshare(CLONE
Tom (Use chromium acct)
2016/12/14 21:10:26
Done. But when I run this as root on Debian, I ge
|
| + _exit(!!ret); |
| } |
| // 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 !status; |
| } |
| bool Credentials::MoveToNewUserNS() { |
| @@ -296,18 +326,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; |
| } |