diff options
author | mcgrathr@chromium.org <mcgrathr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-01 23:19:31 +0000 |
---|---|---|
committer | mcgrathr@chromium.org <mcgrathr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-01 23:19:31 +0000 |
commit | b05df6b03e0d5dc552a96578ea6a8a7e47af407c (patch) | |
tree | 34a9231715fe019e140160b4046e50d76b6357e2 /base | |
parent | a84c55dab98485bb27156a7e99e464ceb9e7f311 (diff) | |
download | chromium_src-b05df6b03e0d5dc552a96578ea6a8a7e47af407c.zip chromium_src-b05df6b03e0d5dc552a96578ea6a8a7e47af407c.tar.gz chromium_src-b05df6b03e0d5dc552a96578ea6a8a7e47af407c.tar.bz2 |
Give base::SharedMemory::CreateAnonymous an executable flag
NaCl on Mac and Linux needs to create a shared memory object that it can
later make executable with mprotect. Express this need in the interface it
uses. Add a test that pages mapped from such an object can later be passed
to mprotect with PROT_EXEC.
This lays the groundwork for a later change that will sometimes use a
different method to allocate an object on Linux when it needs to be
executable. On some Linux distributions, shm_open yields objects whose
mappings cannot be made executable.
BUG= http://code.google.com/p/chromium/issues/detail?id=103377
TEST= SharedMemory.AnonymousExecutable
R=mark@chromium.org,jam@chromium.org,amit@chromium.org,ben@chromium.org
Review URL: http://codereview.chromium.org/8585002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112570 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/shared_memory.h | 41 | ||||
-rw-r--r-- | base/shared_memory_android.cc | 7 | ||||
-rw-r--r-- | base/shared_memory_posix.cc | 25 | ||||
-rw-r--r-- | base/shared_memory_unittest.cc | 22 | ||||
-rw-r--r-- | base/shared_memory_win.cc | 20 |
5 files changed, 83 insertions, 32 deletions
diff --git a/base/shared_memory.h b/base/shared_memory.h index c9dfd6e..8cb27ec 100644 --- a/base/shared_memory.h +++ b/base/shared_memory.h @@ -38,6 +38,29 @@ typedef ino_t SharedMemoryId; // needed. #endif +// Options for creating a shared memory object. +struct SharedMemoryCreateOptions { + SharedMemoryCreateOptions() : name(NULL), size(0), open_existing(false), + executable(false) {} + + // If NULL, the object is anonymous. This pointer is owned by the caller + // and must live through the call to Create(). + const std::string* name; + + // Size of the shared memory object to be created. + // When opening an existing object, this has no effect. + uint32 size; + + // If true, and the shared memory already exists, Create() will open the + // existing shared memory and ignore the size parameter. If false, + // shared memory must not exist. This flag is meaningless unless name is + // non-NULL. + bool open_existing; + + // If true, mappings might need to be made executable later. + bool executable; +}; + // Platform abstraction for shared memory. Provides a C++ wrapper // around the OS primitive for a memory mapped file. class BASE_EXPORT SharedMemory { @@ -74,13 +97,21 @@ class BASE_EXPORT SharedMemory { // Closes a shared memory handle. static void CloseHandle(const SharedMemoryHandle& handle); + // Creates a shared memory object as described by the options struct. + // Returns true on success and false on failure. + bool Create(const SharedMemoryCreateOptions& options); + // Creates and maps an anonymous shared memory segment of size size. // Returns true on success and false on failure. bool CreateAndMapAnonymous(uint32 size); // Creates an anonymous shared memory segment of size size. // Returns true on success and false on failure. - bool CreateAnonymous(uint32 size); + bool CreateAnonymous(uint32 size) { + SharedMemoryCreateOptions options; + options.size = size; + return Create(options); + } // Creates or opens a shared memory segment based on a name. // If open_existing is true, and the shared memory already exists, @@ -88,7 +119,13 @@ class BASE_EXPORT SharedMemory { // If open_existing is false, shared memory must not exist. // size is the size of the block to be created. // Returns true on success, false on failure. - bool CreateNamed(const std::string& name, bool open_existing, uint32 size); + bool CreateNamed(const std::string& name, bool open_existing, uint32 size) { + SharedMemoryCreateOptions options; + options.name = &name; + options.open_existing = open_existing; + options.size = size; + return Create(options); + } // Deletes resources associated with a shared memory segment based on name. // Not all platforms require this call. diff --git a/base/shared_memory_android.cc b/base/shared_memory_android.cc index 72c3a56..8e55e3a 100644 --- a/base/shared_memory_android.cc +++ b/base/shared_memory_android.cc @@ -16,12 +16,13 @@ namespace base { // all the file descriptors from different processes associated with the region // are closed, the memory buffer will go away. -bool SharedMemory::CreateNamed(const std::string& name, - bool open_existing, uint32 size) { +bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { DCHECK_EQ(-1, mapped_file_ ); // "name" is just a label in ashmem. It is visible in /proc/pid/maps. - mapped_file_ = ashmem_create_region(name.c_str(), size); + mapped_file_ = ashmem_create_region( + options.name == NULL ? "" : options.name.c_str(), + options.size); if (-1 == mapped_file_) { DLOG(ERROR) << "Shared memory creation failed"; return false; diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc index 3e5699a..030061a0 100644 --- a/base/shared_memory_posix.cc +++ b/base/shared_memory_posix.cc @@ -98,10 +98,6 @@ bool SharedMemory::CreateAndMapAnonymous(uint32 size) { return CreateAnonymous(size) && Map(size); } -bool SharedMemory::CreateAnonymous(uint32 size) { - return CreateNamed("", false, size); -} - #if !defined(OS_ANDROID) // Chromium mostly only uses the unique/private shmem as specified by // "name == L"". The exception is in the StatsTable. @@ -109,10 +105,9 @@ bool SharedMemory::CreateAnonymous(uint32 size) { // we restart from a crash. (That isn't a new problem, but it is a problem.) // In case we want to delete it later, it may be useful to save the value // of mem_filename after FilePathForMemoryName(). -bool SharedMemory::CreateNamed(const std::string& name, - bool open_existing, uint32 size) { +bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { DCHECK_EQ(-1, mapped_file_); - if (size == 0) return false; + if (options.size == 0) return false; // This function theoretically can block on the disk, but realistically // the temporary files we create will just go into the buffer cache @@ -123,9 +118,9 @@ bool SharedMemory::CreateNamed(const std::string& name, bool fix_size = true; FilePath path; - if (name.empty()) { + if (options.name == NULL || options.name->empty()) { // It doesn't make sense to have a open-existing private piece of shmem - DCHECK(!open_existing); + DCHECK(!options.open_existing); // Q: Why not use the shm_open() etc. APIs? // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU fp = file_util::CreateAndOpenTemporaryShmemFile(&path); @@ -137,11 +132,11 @@ bool SharedMemory::CreateNamed(const std::string& name, file_util::Delete(path, false); } else { - if (!FilePathForMemoryName(name, &path)) + if (!FilePathForMemoryName(*options.name, &path)) return false; fp = file_util::OpenFile(path, "w+x"); - if (fp == NULL && open_existing) { + if (fp == NULL && options.open_existing) { // "w+" will truncate if it already exists. fp = file_util::OpenFile(path, "a+"); fix_size = false; @@ -155,17 +150,17 @@ bool SharedMemory::CreateNamed(const std::string& name, return false; } const uint32 current_size = stat.st_size; - if (current_size != size) { - if (HANDLE_EINTR(ftruncate(fileno(fp), size)) != 0) { + if (current_size != options.size) { + if (HANDLE_EINTR(ftruncate(fileno(fp), options.size)) != 0) { file_util::CloseFile(fp); return false; } - if (fseeko(fp, size, SEEK_SET) != 0) { + if (fseeko(fp, options.size, SEEK_SET) != 0) { file_util::CloseFile(fp); return false; } } - created_size_ = size; + created_size_ = options.size; } if (fp == NULL) { #if !defined(OS_MACOSX) diff --git a/base/shared_memory_unittest.cc b/base/shared_memory_unittest.cc index 9f69a5d..41b8ba5 100644 --- a/base/shared_memory_unittest.cc +++ b/base/shared_memory_unittest.cc @@ -15,6 +15,10 @@ #include "base/mac/scoped_nsautorelease_pool.h" #endif +#if defined(OS_POSIX) +#include <sys/mman.h> +#endif + static const int kNumThreads = 5; static const int kNumTasks = 5; @@ -332,6 +336,24 @@ TEST(SharedMemoryTest, AnonymousPrivate) { } } +#if defined(OS_POSIX) +// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. +TEST(SharedMemoryTest, AnonymousExecutable) { + const uint32 kTestSize = 1 << 16; + + SharedMemory shared_memory; + SharedMemoryCreateOptions options; + options.size = kTestSize; + options.executable = true; + + EXPECT_TRUE(shared_memory.Create(options)); + EXPECT_TRUE(shared_memory.Map(shared_memory.created_size())); + + EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.created_size(), + PROT_READ | PROT_EXEC)); +} +#endif + // On POSIX it is especially important we test shmem across processes, // not just across threads. But the test is enabled on all platforms. class SharedMemoryProcessTest : public MultiProcessTest { diff --git a/base/shared_memory_win.cc b/base/shared_memory_win.cc index 3e5ad36..042eb8b 100644 --- a/base/shared_memory_win.cc +++ b/base/shared_memory_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -74,14 +74,10 @@ bool SharedMemory::CreateAndMapAnonymous(uint32 size) { return CreateAnonymous(size) && Map(size); } -bool SharedMemory::CreateAnonymous(uint32 size) { - return CreateNamed("", false, size); -} - -bool SharedMemory::CreateNamed(const std::string& name, - bool open_existing, uint32 size) { +bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { + DCHECK(!options.executable); DCHECK(!mapped_file_); - if (size == 0) + if (options.size == 0) return false; // NaCl's memory allocator requires 0mod64K alignment and size for @@ -89,22 +85,22 @@ bool SharedMemory::CreateNamed(const std::string& name, // therefore we round the size actually created to the nearest 64K unit. // To avoid client impact, we continue to retain the size as the // actual requested size. - uint32 rounded_size = (size + 0xffff) & ~0xffff; - name_ = ASCIIToWide(name); + uint32 rounded_size = (options.size + 0xffff) & ~0xffff; + name_ = ASCIIToWide(options.name == NULL ? "" : *options.name); mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), name_.empty() ? NULL : name_.c_str()); if (!mapped_file_) return false; - created_size_ = size; + created_size_ = options.size; // Check if the shared memory pre-exists. if (GetLastError() == ERROR_ALREADY_EXISTS) { // If the file already existed, set created_size_ to 0 to show that // we don't know the size. created_size_ = 0; - if (!open_existing) { + if (!options.open_existing) { Close(); return false; } |