| Index: sandbox/linux/services/credentials.cc
 | 
| diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
 | 
| index 291c2cad4450e9a473281255cde6b72009c3852f..ce5eeda78ed177002b4bb4083d452e4fa6edcf2d 100644
 | 
| --- a/sandbox/linux/services/credentials.cc
 | 
| +++ b/sandbox/linux/services/credentials.cc
 | 
| @@ -22,8 +22,11 @@
 | 
|  #include "base/process/launch.h"
 | 
|  #include "base/template_util.h"
 | 
|  #include "base/third_party/valgrind/valgrind.h"
 | 
| +#include "sandbox/linux/services/namespace_utils.h"
 | 
|  #include "sandbox/linux/services/syscall_wrappers.h"
 | 
|  
 | 
| +namespace sandbox {
 | 
| +
 | 
|  namespace {
 | 
|  
 | 
|  bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
 | 
| @@ -48,39 +51,6 @@ struct CapTextFreeDeleter {
 | 
|  // Wrapper to manage the result from libcap2's cap_from_text().
 | 
|  typedef scoped_ptr<char, CapTextFreeDeleter> ScopedCapText;
 | 
|  
 | 
| -struct FILECloser {
 | 
| -  inline void operator()(FILE* f) const {
 | 
| -    DCHECK(f);
 | 
| -    PCHECK(0 == fclose(f));
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -// Don't use ScopedFILE in base since it doesn't check fclose().
 | 
| -// TODO(jln): fix base/.
 | 
| -typedef scoped_ptr<FILE, FILECloser> ScopedFILE;
 | 
| -
 | 
| -static_assert((base::is_same<uid_t, gid_t>::value),
 | 
| -              "uid_t and gid_t should be the same type");
 | 
| -// generic_id_t can be used for either uid_t or gid_t.
 | 
| -typedef uid_t generic_id_t;
 | 
| -
 | 
| -// Write a uid or gid mapping from |id| to |id| in |map_file|.
 | 
| -bool WriteToIdMapFile(const char* map_file, generic_id_t id) {
 | 
| -  ScopedFILE f(fopen(map_file, "w"));
 | 
| -  PCHECK(f);
 | 
| -  const uid_t inside_id = id;
 | 
| -  const uid_t outside_id = id;
 | 
| -  int num = fprintf(f.get(), "%d %d 1\n", inside_id, outside_id);
 | 
| -  if (num < 0) return false;
 | 
| -  // Manually call fflush() to catch permission failures.
 | 
| -  int ret = fflush(f.get());
 | 
| -  if (ret) {
 | 
| -    VLOG(1) << "Could not write to id map file";
 | 
| -    return false;
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
|  // Checks that the set of RES-uids and the set of RES-gids have
 | 
|  // one element each and return that element in |resuid| and |resgid|
 | 
|  // respectively. It's ok to pass NULL as one or both of the ids.
 | 
| @@ -97,6 +67,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 +89,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 +129,6 @@ void CheckCloneNewUserErrno(int error) {
 | 
|  
 | 
|  }  // namespace.
 | 
|  
 | 
| -namespace sandbox {
 | 
| -
 | 
|  bool Credentials::DropAllCapabilities() {
 | 
|    ScopedCap cap(cap_init());
 | 
|    CHECK(cap);
 | 
| @@ -169,7 +155,7 @@ scoped_ptr<std::string> Credentials::GetCurrentCapString() {
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| -bool Credentials::SupportsNewUserNS() {
 | 
| +bool Credentials::CanCreateProcessInNewUserNS() {
 | 
|    // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
 | 
|    // so always consider UserNS unsupported there.
 | 
|    if (IsRunningOnValgrind()) {
 | 
| @@ -222,8 +208,8 @@ bool Credentials::MoveToNewUserNS() {
 | 
|    DCHECK(GetRESIds(NULL, NULL));
 | 
|    const char kGidMapFile[] = "/proc/self/gid_map";
 | 
|    const char kUidMapFile[] = "/proc/self/uid_map";
 | 
| -  CHECK(WriteToIdMapFile(kGidMapFile, gid));
 | 
| -  CHECK(WriteToIdMapFile(kUidMapFile, uid));
 | 
| +  CHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
 | 
| +  CHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
 | 
|    DCHECK(GetRESIds(NULL, NULL));
 | 
|    return true;
 | 
|  }
 | 
| 
 |