Index: base/memory/shared_memory_unittest.cc |
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc |
index 892fd7f1a590b0d20b8f9e6289b07a225c8676fa..93b8d839ba0992eb225b150403c7c1aa12d2f1c2 100644 |
--- a/base/memory/shared_memory_unittest.cc |
+++ b/base/memory/shared_memory_unittest.cc |
@@ -20,12 +20,18 @@ |
#endif |
#if defined(OS_POSIX) |
+#include <errno.h> |
+#include <fcntl.h> |
#include <sys/mman.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
#include <unistd.h> |
#endif |
+#if defined(OS_WIN) |
+#include "base/win/scoped_handle.h" |
+#endif |
+ |
static const int kNumThreads = 5; |
static const int kNumTasks = 5; |
@@ -361,6 +367,69 @@ TEST(SharedMemoryTest, AnonymousPrivate) { |
} |
} |
+TEST(SharedMemoryTest, ShareReadOnly) { |
+ StringPiece contents = "Hello World"; |
+ |
+ SharedMemory writable_shmem; |
+ ASSERT_TRUE(writable_shmem.CreateAndMapAnonymous(contents.size())); |
+ memcpy(writable_shmem.memory(), contents.data(), contents.size()); |
+ |
+ SharedMemoryHandle readonly_handle; |
+ ASSERT_TRUE(writable_shmem.ShareReadOnlyToProcess(GetCurrentProcessHandle(), |
+ &readonly_handle)); |
+ SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true); |
+ |
+ ASSERT_TRUE(readonly_shmem.Map(contents.size())); |
+ EXPECT_EQ(contents, |
+ StringPiece(static_cast<const char*>(readonly_shmem.memory()), |
+ contents.size())); |
+ |
+ // We'd like to check that if we send the read-only segment to another |
+ // process, then that other process can't reopen it read/write. (Since that |
+ // would be a security hole.) Setting up multiple processes is hard in a |
+ // unittest, so this test checks that the *current* process can't reopen the |
+ // segment read/write. I think the test here is stronger than we actually |
+ // care about, but there's a remote possibility that sending a file over a |
+ // pipe would transform it into read/write. |
+ SharedMemoryHandle handle = readonly_shmem.handle(); |
+ |
+#if defined(OS_POSIX) |
+ EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE) |
+ << "The descriptor itself should be read-only."; |
+ |
+ errno = 0; |
+ void* writable = mmap(NULL, |
+ readonly_shmem.mapped_size(), |
+ PROT_READ | PROT_WRITE, |
+ MAP_SHARED, |
+ handle.fd, |
+ 0); |
+ int mmap_errno = errno; |
+ EXPECT_EQ(MAP_FAILED, writable) |
+ << "It shouldn't be possible to re-mmap the descriptor writable."; |
+ EXPECT_EQ(EACCES, mmap_errno); |
+ if (writable != MAP_FAILED) |
+ EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size())); |
+ |
+#elif defined(OS_WIN) |
+ EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0)) |
+ << "Shouldn't be able to map memory writable."; |
+ |
+ base::win::ScopedHandle writable_handle; |
+ EXPECT_EQ(0, |
+ ::DuplicateHandle(GetCurrentProcess(), |
+ handle, |
+ GetCurrentProcess, |
+ writable_handle.Receive(), |
+ FILE_MAP_ALL_ACCESS, |
+ false, |
+ 0)) |
+ << "Shouldn't be able to duplicate the handle into a writable one."; |
+#else |
+#error Unexpected platform; write a test that tries to make 'handle' writable. |
+#endif // defined(OS_POSIX) || defined(OS_WIN) |
+} |
+ |
TEST(SharedMemoryTest, MapAt) { |
ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32)); |
const size_t kCount = SysInfo::VMAllocationGranularity(); |