Index: sandbox/linux/services/credentials.cc |
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc |
index 291c2cad4450e9a473281255cde6b72009c3852f..be03e15ac78382b9280a3610df41b5eed0cac02c 100644 |
--- a/sandbox/linux/services/credentials.cc |
+++ b/sandbox/linux/services/credentials.cc |
@@ -24,6 +24,8 @@ |
#include "base/third_party/valgrind/valgrind.h" |
#include "sandbox/linux/services/syscall_wrappers.h" |
+namespace sandbox { |
+ |
namespace { |
bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } |
@@ -97,6 +99,17 @@ bool GetRESIds(uid_t* resuid, gid_t* resgid) { |
return true; |
} |
+const int kExitSuccess = 0; |
+ |
+int ChrootToSelfFdinfo(void*) { |
+ RAW_CHECK(chroot("/proc/self/fdinfo/") == 0); |
+ |
+ // CWD is essentially an implicit file descriptor, so be careful to not |
+ // leave it behind. |
+ RAW_CHECK(chdir("/") == 0); |
+ _exit(kExitSuccess); |
+} |
+ |
// chroot() to an empty dir that is "safe". To be safe, it must not contain |
// any subdirectory (chroot-ing there would allow a chroot escape) and it must |
// be impossible to create an empty directory there. |
@@ -108,25 +121,32 @@ bool GetRESIds(uid_t* resuid, gid_t* resgid) { |
// 3. The process dies |
// After (3) happens, the directory is not available anymore in /proc. |
bool ChrootToSafeEmptyDir() { |
- // We do not use a thread because when we are in a PID namespace, we cannot |
- // easily get a handle to the /proc/tid directory for the thread (since /proc |
- // may not be aware of the PID namespace). With a process, we can just use |
- // /proc/self. |
- pid_t pid = base::ForkWithFlags(SIGCHLD | CLONE_FS, nullptr, nullptr); |
+ // We need to chroot to a fdinfo that is unique to a process and have that |
+ // process die. |
+ // 1. We don't want to simply fork() because duplicating the page tables is |
+ // slow with a big address space. |
+ // 2. We do not use a regular thread (that would unshare CLONE_FILES) because |
+ // when we are in a PID namespace, we cannot easily get a handle to the |
+ // /proc/tid directory for the thread (since /proc may not be aware of the |
+ // PID namespace). With a process, we can just use /proc/self. |
+ pid_t pid = -1; |
+ char stack_buf[PTHREAD_STACK_MIN]; |
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ |
+ defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY) |
+ // The stack grows downward. |
+ void* stack = stack_buf + sizeof(stack_buf); |
+#else |
+#error "Unsupported architecture" |
+#endif |
+ pid = clone(ChrootToSelfFdinfo, stack, |
+ CLONE_VM | CLONE_VFORK | CLONE_FS | SIGCHLD, nullptr, nullptr, |
+ nullptr, nullptr); |
PCHECK(pid != -1); |
- if (pid == 0) { |
- RAW_CHECK(chroot("/proc/self/fdinfo/") == 0); |
- |
- // CWD is essentially an implicit file descriptor, so be careful to not |
- // leave it behind. |
- RAW_CHECK(chdir("/") == 0); |
- _exit(0); |
- } |
int status = -1; |
PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); |
- return status == 0; |
+ return kExitSuccess == status; |
} |
// CHECK() that an attempt to move to a new user namespace raised an expected |
@@ -141,8 +161,6 @@ void CheckCloneNewUserErrno(int error) { |
} // namespace. |
-namespace sandbox { |
- |
bool Credentials::DropAllCapabilities() { |
ScopedCap cap(cap_init()); |
CHECK(cap); |