Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(305)

Unified Diff: base/memory/shared_memory_unittest.cc

Issue 27265002: Implement SharedMemory::NewAnonymousReadOnly(contents). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix signedness on Mac Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/memory/shared_memory_posix.cc ('k') | base/memory/shared_memory_win.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..d923b26a0ba445e90f7dd52e8c344582e1ea054d 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -7,7 +7,9 @@
#include "base/memory/shared_memory.h"
#include "base/process/kill.h"
#include "base/rand_util.h"
+#include "base/safe_numerics.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
#include "base/test/multiprocess_test.h"
#include "base/threading/platform_thread.h"
@@ -20,6 +22,8 @@
#endif
#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -361,6 +365,107 @@ TEST(SharedMemoryTest, AnonymousPrivate) {
}
}
+TEST(SharedMemoryTest, AnonymousReadOnly) {
+ StringPiece contents = "Hello World";
+ scoped_ptr<SharedMemory> shmem(
+ SharedMemory::NewAnonymousReadOnly("Hello World"));
+
+ ASSERT_TRUE(shmem->Map(contents.size()));
+ EXPECT_EQ(
+ contents,
+ StringPiece(static_cast<const char*>(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 = 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,
+ 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);
+
+ struct stat fd_stat;
+ errno = 0;
+ EXPECT_EQ(0, fstat(handle.fd, &fd_stat)) << strerror(errno);
+ EXPECT_EQ(0400, checked_numeric_cast<int>(fd_stat.st_mode & 0777))
+ << "inode should be read-only";
+ EXPECT_EQ(0U, fd_stat.st_nlink) << "inode should be unlinked";
+ EXPECT_EQ(geteuid(), fd_stat.st_uid)
+ << "inode should be owned by current user";
+
+ if (0 == access("/dev/fd", X_OK)) {
+ // Try to re-open through /dev/fd. This is an end-run around the notion of
+ // an FD as a capability.
+ const std::string shmem_path = StringPrintf("/dev/fd/%d", handle.fd);
+ errno = 0;
+ int readable_fd = open(shmem_path.c_str(), O_RDONLY);
+ EXPECT_NE(-1, readable_fd) << strerror(errno);
+ close(readable_fd);
+
+ errno = 0;
+ int writable_fd = open(shmem_path.c_str(), O_WRONLY);
+ int open_writable_errno = errno;
+ EXPECT_EQ(-1, writable_fd);
+ EXPECT_EQ(EACCES, open_writable_errno) << strerror(open_writable_errno);
+ close(writable_fd);
+
+ // However, if we explicitly make the entry in /dev/fd writable first, the
+ // open() call successfully creates a writable file on Linux. The sandbox
+ // has to prevent opening this path. TODO(jln): Write a test that attacks
+ // this from inside the sandbox.
+ errno = 0;
+ EXPECT_EQ(0, fchmod(handle.fd, S_IRUSR | S_IWUSR)) << strerror(errno);
+
+ errno = 0;
+ writable_fd = open(shmem_path.c_str(), O_WRONLY);
+ open_writable_errno = errno;
+ // On Linux, opening the file /dev/fd/N where 'N' is a read-only file
+ // descriptor, can produce a writable file descriptor if the inode is
+ // writable (see the fchmod above). Mac appears to restrict the open() call
+ // appropriately. Other systems might let the open() succeed but still
+ // produce a read-only descriptor.
+#if !defined(OS_LINUX)
+ EXPECT_EQ(-1, writable_fd);
+ EXPECT_EQ(EACCES, open_writable_errno) << strerror(open_writable_errno);
+#endif
+ close(writable_fd);
+ }
+
+#elif defined(OS_WIN)
+ EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0))
+ << "Shouldn't be able to map memory writable.";
+
+ SharedMemoryHandle writable_handle = INVALID_HANDLE_VALUE;
+ EXPECT_EQ(0,
+ ::DuplicateHandle(GetCurrentProcess(),
Will Harris 2013/10/16 17:01:03 should probably CloseHandle after this succeeds, o
Jeffrey Yasskin 2013/10/16 22:27:53 Thanks, done with ScopedHandle.
+ handle,
+ GetCurrentProcess,
+ &writable_handle,
+ 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
+}
+
TEST(SharedMemoryTest, MapAt) {
ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
const size_t kCount = SysInfo::VMAllocationGranularity();
« no previous file with comments | « base/memory/shared_memory_posix.cc ('k') | base/memory/shared_memory_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698