Backport http://codereview.chromium.org/8800025 to fix issues with noexec /dev/shm diff --git a/base/file_util.h b/base/file_util.h index 90ec1ae..78827e9 100644 --- a/base/file_util.h +++ b/base/file_util.h @@ -259,7 +259,7 @@ BASE_EXPORT bool IsDirectoryEmpty(const FilePath& dir_path); BASE_EXPORT bool GetTempDir(FilePath* path); // Get a temporary directory for shared memory files. // Only useful on POSIX; redirects to GetTempDir() on Windows. -BASE_EXPORT bool GetShmemTempDir(FilePath* path); +BASE_EXPORT bool GetShmemTempDir(FilePath* path, bool executable); // Get the home directory. This is more complicated than just getenv("HOME") // as it knows to fall back on getpwent() etc. @@ -279,7 +279,10 @@ BASE_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir, // Returns a handle to the opened file or NULL if an error occured. BASE_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path); // Like above but for shmem files. Only useful for POSIX. -BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(FilePath* path); +// The executable flag says the file needs to support using +// mprotect with PROT_EXEC after mapping. +BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, + bool executable); // Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|. BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path); diff --git a/base/file_util_android.cc b/base/file_util_android.cc index eff3a46..6807d8d 100644 --- a/base/file_util_android.cc +++ b/base/file_util_android.cc @@ -8,7 +8,7 @@ namespace file_util { -bool GetShmemTempDir(FilePath* path) { +bool GetShmemTempDir(FilePath* path, bool executable) { *path = FilePath("/data/local/tmp"); return true; } diff --git a/base/file_util_mac.mm b/base/file_util_mac.mm index 95d4f25..bb4975d 100644 --- a/base/file_util_mac.mm +++ b/base/file_util_mac.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2010 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. @@ -22,7 +22,7 @@ bool GetTempDir(FilePath* path) { return true; } -bool GetShmemTempDir(FilePath* path) { +bool GetShmemTempDir(FilePath* path, bool executable) { return GetTempDir(path); } diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index 582f70e..5c14abd 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -481,9 +481,9 @@ bool CreateTemporaryFile(FilePath* path) { return true; } -FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) { +FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { FilePath directory; - if (!GetShmemTempDir(&directory)) + if (!GetShmemTempDir(&directory, executable)) return NULL; return CreateAndOpenTemporaryFileInDir(directory, path); @@ -910,15 +910,52 @@ bool GetTempDir(FilePath* path) { } #if !defined(OS_ANDROID) -bool GetShmemTempDir(FilePath* path) { + #if defined(OS_LINUX) - *path = FilePath("/dev/shm"); - return true; -#else - return GetTempDir(path); -#endif +// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. +// This depends on the mount options used for /dev/shm, which vary among +// different Linux distributions and possibly local configuration. It also +// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm +// but its kernel allows mprotect with PROT_EXEC anyway. + +namespace { + +bool DetermineDevShmExecutable() { + bool result = false; + FilePath path; + int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path); + if (fd >= 0) { + ScopedFD shm_fd_closer(&fd); + Delete(path, false); + size_t pagesize = sysconf(_SC_PAGESIZE); + void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); + if (mapping != MAP_FAILED) { + if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) + result = true; + munmap(mapping, pagesize); + } + } + return result; } + +}; // namespace +#endif // defined(OS_LINUX) + +bool GetShmemTempDir(FilePath* path, bool executable) { +#if defined(OS_LINUX) + bool use_dev_shm = true; + if (executable) { + static const bool s_dev_shm_executable = DetermineDevShmExecutable(); + use_dev_shm = s_dev_shm_executable; + } + if (use_dev_shm) { + *path = FilePath("/dev/shm"); + return true; + } #endif + return GetTempDir(path); +} +#endif // !defined(OS_ANDROID) FilePath GetHomeDir() { const char* home_dir = getenv("HOME"); diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc index 00cacd6..a9f9377 100644 --- a/base/file_util_unittest.cc +++ b/base/file_util_unittest.cc @@ -1545,7 +1545,7 @@ TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) { TEST_F(FileUtilTest, GetShmemTempDirTest) { FilePath dir; - EXPECT_TRUE(file_util::GetShmemTempDir(&dir)); + EXPECT_TRUE(file_util::GetShmemTempDir(&dir, false)); EXPECT_TRUE(file_util::DirectoryExists(dir)); } diff --git a/base/file_util_win.cc b/base/file_util_win.cc index 8d9fbde..a6720a5 100644 --- a/base/file_util_win.cc +++ b/base/file_util_win.cc @@ -556,7 +556,7 @@ bool GetTempDir(FilePath* path) { return true; } -bool GetShmemTempDir(FilePath* path) { +bool GetShmemTempDir(FilePath* path, bool executable) { return GetTempDir(path); } @@ -576,7 +576,7 @@ bool CreateTemporaryFile(FilePath* path) { return false; } -FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) { +FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { base::ThreadRestrictions::AssertIOAllowed(); return CreateAndOpenTemporaryFile(path); } diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc index 030061a..a66c859 100644 --- a/base/shared_memory_posix.cc +++ b/base/shared_memory_posix.cc @@ -123,7 +123,7 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { 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); + fp = file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable); // Deleting the file prevents anyone else from mapping it in // (making it private), and prevents the need for cleanup (once @@ -317,7 +317,7 @@ bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, DCHECK_EQ(std::string::npos, mem_name.find('\0')); FilePath temp_dir; - if (!file_util::GetShmemTempDir(&temp_dir)) + if (!file_util::GetShmemTempDir(&temp_dir, false)) return false; #if !defined(OS_MACOSX) -- 1.7.6.1