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; |
} |