Commit message: None
CVE: CVE-2013-2905
CWE: CWE-264
Vulnerability description: The SharedMemory::Create function in memory/shared_memory_posix.cc in Google Chrome before 29.0.1547.57 uses weak permissions under /dev/shm/, which allows attackers to obtain sensitive information via direct access to a POSIX shared-memory file.

Project: Chrome

void SharedMemory::Close() {
  Unmap();

  if (mapped_file_ > 0) {
    if (HANDLE_EINTR(close(mapped_file_)) < 0)
      PLOG(ERROR) << "close";
    mapped_file_ = -1;
  }
}

Project: Chrome

void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
  DCHECK_GE(handle.fd, 0);
  if (HANDLE_EINTR(close(handle.fd)) < 0)
    DPLOG(ERROR) << "close";
}

Project: Chrome

bool SharedMemory::Delete(const std::string& name) {
  FilePath path;
  if (!FilePathForMemoryName(name, &path))
    return false;

  if (file_util::PathExists(path)) {
    return base::Delete(path, false);
  }

  return true;
}

Project: Chrome

bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
                                         FilePath* path) {
  DCHECK_EQ(std::string::npos, mem_name.find('/'));
  DCHECK_EQ(std::string::npos, mem_name.find('\0'));

  FilePath temp_dir;
  if (!file_util::GetShmemTempDir(&temp_dir, false))
    return false;

#if !defined(OS_MACOSX)
#if defined(GOOGLE_CHROME_BUILD)
  std::string name_base = std::string("com.google.Chrome");
#else
  std::string name_base = std::string("org.chromium.Chromium");
#endif
#else  // OS_MACOSX
  std::string name_base = std::string(base::mac::BaseBundleID());
#endif  // OS_MACOSX
  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
  return true;
}

Project: Chrome

size_t SharedMemory::GetHandleLimit() {
  return base::GetMaxFds();
}

Project: Chrome

bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
  return handle.fd >= 0;
}

Project: Chrome

void SharedMemory::Lock() {
  g_thread_lock_.Get().Acquire();
  LockOrUnlockCommon(F_LOCK);
}

Project: Chrome

void SharedMemory::LockOrUnlockCommon(int function) {
  DCHECK_GE(mapped_file_, 0);
  while (lockf(mapped_file_, function, 0) < 0) {
    if (errno == EINTR) {
      continue;
    } else if (errno == ENOLCK) {
      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
      continue;
    } else {
      NOTREACHED() << "lockf() failed."
                   << " function:" << function
                   << " fd:" << mapped_file_
                   << " errno:" << errno
                   << " msg:" << safe_strerror(errno);
    }
  }
}

Project: Chrome

bool SharedMemory::MapAt(off_t offset, size_t bytes) {
  if (mapped_file_ == -1)
    return false;

  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
    return false;

#if defined(OS_ANDROID)
  if (bytes == 0) {
    DCHECK_EQ(0, offset);
    int ashmem_bytes = ashmem_get_size_region(mapped_file_);
    if (ashmem_bytes < 0)
      return false;
    bytes = ashmem_bytes;
  }
#endif

  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
                 MAP_SHARED, mapped_file_, offset);

  bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
  if (mmap_succeeded) {
    mapped_size_ = bytes;
    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
  } else {
    memory_ = NULL;
  }

  return mmap_succeeded;
}

Project: Chrome

SharedMemoryHandle SharedMemory::NULLHandle() {
  return SharedMemoryHandle();
}

Project: Chrome

bool SharedMemory::Open(const std::string& name, bool read_only) {
  FilePath path;
  if (!FilePathForMemoryName(name, &path))
    return false;

  read_only_ = read_only;

  const char *mode = read_only ? "r" : "r+";
  FILE *fp = file_util::OpenFile(path, mode);
  return PrepareMapFile(fp);
}

Project: Chrome

bool SharedMemory::PrepareMapFile(FILE *fp) {
  DCHECK_EQ(-1, mapped_file_);
  if (fp == NULL) return false;

  base::ThreadRestrictions::ScopedAllowIO allow_io;

  file_util::ScopedFILE file_closer(fp);

  mapped_file_ = dup(fileno(fp));
  if (mapped_file_ == -1) {
    if (errno == EMFILE) {
      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
      return false;
    } else {
      NOTREACHED() << "Call to dup failed, errno=" << errno;
    }
  }

  struct stat st;
  if (fstat(mapped_file_, &st))
    NOTREACHED();
  inode_ = st.st_ino;

  return true;
}

Project: Chrome

bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                        SharedMemoryHandle *new_handle,
                                        bool close_self) {
  const int new_fd = dup(mapped_file_);
  if (new_fd < 0) {
    DPLOG(ERROR) << "dup() failed.";
    return false;
  }

  new_handle->fd = new_fd;
  new_handle->auto_close = true;

  if (close_self)
    Close();

  return true;
}

Project: Chrome

SharedMemory::SharedMemory()
    : mapped_file_(-1),
      inode_(0),
      mapped_size_(0),
      memory_(NULL),
      read_only_(false),
      requested_size_(0) {
}

Project: Chrome

void SharedMemory::Unlock() {
  LockOrUnlockCommon(F_ULOCK);
  g_thread_lock_.Get().Release();
}

Project: Chrome

bool SharedMemory::Unmap() {
  if (memory_ == NULL)
    return false;

  munmap(memory_, mapped_size_);
  memory_ = NULL;
  mapped_size_ = 0;
  return true;
}

Project: Chrome

SharedMemoryHandle SharedMemory::handle() const {
  return FileDescriptor(mapped_file_, false);
}

Project: Chrome

SharedMemory::~SharedMemory() {
  Close();
}

Project: Chrome

  explicit MultipleLockThread(int id) : id_(id) {}

Project: Chrome

  explicit MultipleThreadMain(int16 id) : id_(id) {}

Project: Chrome

  static int TaskTestMain() {
    int errors = 0;
#if defined(OS_MACOSX)
    mac::ScopedNSAutoreleasePool pool;
#endif
    const uint32 kDataSize = 1024;
    SharedMemory memory;
    bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
    EXPECT_TRUE(rv);
    if (rv != true)
      errors++;
    rv = memory.Map(kDataSize);
    EXPECT_TRUE(rv);
    if (rv != true)
      errors++;
    int *ptr = static_cast<int*>(memory.memory());

    for (int idx = 0; idx < 20; idx++) {
      memory.Lock();
      int i = (1 << 16) + idx;
      *ptr = i;
      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
      if (*ptr != i)
        errors++;
      memory.Unlock();
    }

    memory.Close();
    return errors;
  }

Project: Chrome

  virtual ~MultipleLockThread() {}

Project: Chrome

  virtual ~MultipleThreadMain() {}