diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-15 14:18:00 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-15 14:00:37 +0000 |
commit | 66a2147d838e293f4a5db7711c8eba4e6faaaf0f (patch) | |
tree | 61ad99912355f5b6cc603d9b1dfadd77b950ce98 /chromium/base | |
parent | da51f56cc21233c2d30f0fe0d171727c3102b2e0 (diff) | |
download | qtwebengine-chromium-66a2147d838e293f4a5db7711c8eba4e6faaaf0f.tar.gz |
BASELINE: Update Chromium to 65.0.3325.75
Change-Id: I5485bc5c111539356276457516584fa5737f07d8
Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'chromium/base')
-rw-r--r-- | chromium/base/i18n/icu_util.cc | 6 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory.h | 2 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory_android.cc | 27 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory_handle.h | 20 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory_handle_android.cc | 52 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory_posix.cc | 20 | ||||
-rw-r--r-- | chromium/base/memory/shared_memory_unittest.cc | 114 | ||||
-rw-r--r-- | chromium/base/metrics/field_trial.cc | 21 | ||||
-rw-r--r-- | chromium/base/metrics/field_trial.h | 1 | ||||
-rw-r--r-- | chromium/base/metrics/field_trial_unittest.cc | 25 | ||||
-rw-r--r-- | chromium/base/test/BUILD.gn | 2 |
11 files changed, 267 insertions, 23 deletions
diff --git a/chromium/base/i18n/icu_util.cc b/chromium/base/i18n/icu_util.cc index 4a1327bf156..6caf730306a 100644 --- a/chromium/base/i18n/icu_util.cc +++ b/chromium/base/i18n/icu_util.cc @@ -202,6 +202,8 @@ bool InitializeICUWithFileDescriptorInternal( icu::UnicodeString(FALSE, timezone_id.data(), timezone_id.length()))); } #endif + // Never try to load ICU data from files. + udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); return err == U_ZERO_ERROR; } #endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE @@ -243,6 +245,8 @@ bool InitializeICUFromRawMemory(const uint8_t* raw_memory) { UErrorCode err = U_ZERO_ERROR; udata_setCommonData(const_cast<uint8_t*>(raw_memory), &err); + // Never try to load ICU data from files. + udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); return err == U_ZERO_ERROR; #else return true; @@ -279,6 +283,8 @@ bool InitializeICU() { UErrorCode err = U_ZERO_ERROR; udata_setCommonData(reinterpret_cast<void*>(addr), &err); + // Never try to load ICU data from files. + udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); result = (err == U_ZERO_ERROR); #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC) // The ICU data is statically linked. diff --git a/chromium/base/memory/shared_memory.h b/chromium/base/memory/shared_memory.h index 9a4159855b6..2ab7870f4f0 100644 --- a/chromium/base/memory/shared_memory.h +++ b/chromium/base/memory/shared_memory.h @@ -226,7 +226,7 @@ class BASE_EXPORT SharedMemory { // before being mapped. bool external_section_ = false; string16 name_; -#else +#elif !defined(OS_ANDROID) && !defined(OS_FUCHSIA) // If valid, points to the same memory region as shm_, but with readonly // permissions. SharedMemoryHandle readonly_shm_; diff --git a/chromium/base/memory/shared_memory_android.cc b/chromium/base/memory/shared_memory_android.cc index c426ac3bcce..c126767c6b3 100644 --- a/chromium/base/memory/shared_memory_android.cc +++ b/chromium/base/memory/shared_memory_android.cc @@ -33,21 +33,13 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { return false; } - int err = ashmem_set_prot_region(shm_.GetHandle(), - PROT_READ | PROT_WRITE | PROT_EXEC); + int flags = PROT_READ | PROT_WRITE | (options.executable ? PROT_EXEC : 0); + int err = ashmem_set_prot_region(shm_.GetHandle(), flags); if (err < 0) { DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; return false; } - // Android doesn't appear to have a way to drop write access on an ashmem - // segment for a single descriptor. http://crbug.com/320865 - readonly_shm_ = shm_.Duplicate(); - if (!readonly_shm_.IsValid()) { - DPLOG(ERROR) << "dup() failed"; - return false; - } - requested_size_ = options.size; return true; @@ -65,4 +57,19 @@ bool SharedMemory::Open(const std::string& name, bool read_only) { return false; } +void SharedMemory::Close() { + if (shm_.IsValid()) { + shm_.Close(); + shm_ = SharedMemoryHandle(); + } +} + +SharedMemoryHandle SharedMemory::GetReadOnlyHandle() const { + // There are no read-only Ashmem descriptors on Android. + // Instead, the protection mask is a property of the region itself. + SharedMemoryHandle handle = shm_.Duplicate(); + handle.SetReadOnly(); + return handle; +} + } // namespace base diff --git a/chromium/base/memory/shared_memory_handle.h b/chromium/base/memory/shared_memory_handle.h index 22b9737b4b9..e8b1a797c9c 100644 --- a/chromium/base/memory/shared_memory_handle.h +++ b/chromium/base/memory/shared_memory_handle.h @@ -174,6 +174,21 @@ class BASE_EXPORT SharedMemoryHandle { size_t size, const base::UnguessableToken& guid); AHardwareBuffer* GetMemoryObject() const; + + // Marks the current file descriptor as read-only, for the purpose of + // mapping. This is independent of the region's read-only status. + void SetReadOnly() { read_only_ = true; } + + // Returns true iff the descriptor is to be used for read-only + // mappings. + bool IsReadOnly() const { return read_only_; } + + // Returns true iff the corresponding region is read-only. + bool IsRegionReadOnly() const; + + // Try to set the region read-only. This will fail any future attempt + // at read-write mapping. + bool SetRegionReadOnly() const; #endif #if defined(OS_POSIX) && !defined(OS_FUCHSIA) @@ -199,6 +214,8 @@ class BASE_EXPORT SharedMemoryHandle { private: #if defined(OS_MACOSX) && !defined(OS_IOS) friend class SharedMemory; + friend bool CheckReadOnlySharedMemoryHandleForTesting( + SharedMemoryHandle handle); Type type_ = MACH; @@ -218,6 +235,8 @@ class BASE_EXPORT SharedMemoryHandle { }; }; #elif defined(OS_ANDROID) + friend class SharedMemory; + // Each instance of a SharedMemoryHandle is either INVALID, or backed by an // ashmem fd, or backed by an AHardwareBuffer. |type_| determines the backing // member. @@ -225,6 +244,7 @@ class BASE_EXPORT SharedMemoryHandle { FileDescriptor file_descriptor_; AHardwareBuffer* memory_object_ = nullptr; bool ownership_passes_to_ipc_ = false; + bool read_only_ = false; #elif defined(OS_FUCHSIA) zx_handle_t handle_ = ZX_HANDLE_INVALID; bool ownership_passes_to_ipc_ = false; diff --git a/chromium/base/memory/shared_memory_handle_android.cc b/chromium/base/memory/shared_memory_handle_android.cc index 69d32032c6d..2704213fc0b 100644 --- a/chromium/base/memory/shared_memory_handle_android.cc +++ b/chromium/base/memory/shared_memory_handle_android.cc @@ -4,6 +4,7 @@ #include "base/memory/shared_memory_handle.h" +#include <sys/mman.h> #include <unistd.h> #include "base/android/android_hardware_buffer_compat.h" @@ -11,9 +12,19 @@ #include "base/posix/eintr_wrapper.h" #include "base/posix/unix_domain_socket.h" #include "base/unguessable_token.h" +#include "third_party/ashmem/ashmem.h" namespace base { +static int GetAshmemRegionProtectionMask(int fd) { + int prot = ashmem_get_prot_region(fd); + if (prot < 0) { + DPLOG(ERROR) << "ashmem_get_prot_region"; + return -1; + } + return prot; +} + SharedMemoryHandle::SharedMemoryHandle() {} SharedMemoryHandle::SharedMemoryHandle( @@ -154,11 +165,15 @@ SharedMemoryHandle SharedMemoryHandle::Duplicate() const { return SharedMemoryHandle(); case Type::ASHMEM: { DCHECK(IsValid()); + SharedMemoryHandle result; int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd)); - if (duped_handle < 0) - return SharedMemoryHandle(); - return SharedMemoryHandle(FileDescriptor(duped_handle, true), GetSize(), - GetGUID()); + if (duped_handle >= 0) { + result = SharedMemoryHandle(FileDescriptor(duped_handle, true), + GetSize(), GetGUID()); + if (IsReadOnly()) + result.SetReadOnly(); + } + return result; } case Type::ANDROID_HARDWARE_BUFFER: DCHECK(IsValid()); @@ -195,4 +210,33 @@ bool SharedMemoryHandle::OwnershipPassesToIPC() const { } } +bool SharedMemoryHandle::IsRegionReadOnly() const { + if (type_ != Type::ASHMEM) + return false; + + int prot = GetAshmemRegionProtectionMask(file_descriptor_.fd); + return (prot >= 0 && (prot & PROT_WRITE) == 0); +} + +bool SharedMemoryHandle::SetRegionReadOnly() const { + DCHECK_EQ(type_, Type::ASHMEM); + int fd = file_descriptor_.fd; + int prot = GetAshmemRegionProtectionMask(fd); + if (prot < 0) + return false; + + if ((prot & PROT_WRITE) == 0) { + // Region is already read-only. + return true; + } + + prot &= ~PROT_WRITE; + int ret = ashmem_set_prot_region(fd, prot); + if (ret != 0) { + DPLOG(ERROR) << "ashmem_set_prot_region"; + return false; + } + return true; +} + } // namespace base diff --git a/chromium/base/memory/shared_memory_posix.cc b/chromium/base/memory/shared_memory_posix.cc index f0e4f95b84f..f9d71f4739c 100644 --- a/chromium/base/memory/shared_memory_posix.cc +++ b/chromium/base/memory/shared_memory_posix.cc @@ -281,6 +281,22 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) { return false; bytes = ashmem_bytes; } + + // Sanity check. This shall catch invalid uses of the SharedMemory APIs + // but will not protect against direct mmap() attempts. + if (shm_.IsReadOnly()) { + // Use a DCHECK() to call writable mappings with read-only descriptors + // in debug builds immediately. Return an error for release builds + // or during unit-testing (assuming a ScopedLogAssertHandler was installed). + DCHECK(read_only_) + << "Trying to map a region writable with a read-only descriptor."; + if (!read_only_) { + return false; + } + if (!shm_.SetRegionReadOnly()) { // Ensure the region is read-only. + return false; + } + } #endif memory_ = mmap(nullptr, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), @@ -326,6 +342,7 @@ SharedMemoryHandle SharedMemory::TakeHandle() { return handle_copy; } +#if !defined(OS_ANDROID) void SharedMemory::Close() { if (shm_.IsValid()) { shm_.Close(); @@ -337,7 +354,6 @@ void SharedMemory::Close() { } } -#if !defined(OS_ANDROID) // For the given shmem named |mem_name|, return a filename to mmap() // (and possibly create). Modifies |filename|. Return false on // error, or true of we are happy. @@ -361,11 +377,11 @@ bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, *path = temp_dir.AppendASCII(name_base + mem_name); return true; } -#endif // !defined(OS_ANDROID) SharedMemoryHandle SharedMemory::GetReadOnlyHandle() const { CHECK(readonly_shm_.IsValid()); return readonly_shm_.Duplicate(); } +#endif // !defined(OS_ANDROID) } // namespace base diff --git a/chromium/base/memory/shared_memory_unittest.cc b/chromium/base/memory/shared_memory_unittest.cc index d3c31dbd569..b8f197807df 100644 --- a/chromium/base/memory/shared_memory_unittest.cc +++ b/chromium/base/memory/shared_memory_unittest.cc @@ -11,12 +11,15 @@ #include "base/atomicops.h" #include "base/base_switches.h" +#include "base/bind.h" #include "base/command_line.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/shared_memory_handle.h" #include "base/process/kill.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/sys_info.h" #include "base/test/multiprocess_test.h" @@ -382,6 +385,11 @@ TEST_P(SharedMemoryTest, GetReadOnlyHandle) { contents.size())); EXPECT_TRUE(readonly_shmem.Unmap()); +#if defined(OS_ANDROID) + // On Android, mapping a region through a read-only descriptor makes the + // region read-only. Any writable mapping attempt should fail. + ASSERT_FALSE(writable_shmem.Map(contents.size())); +#else // Make sure the writable instance is still writable. ASSERT_TRUE(writable_shmem.Map(contents.size())); StringPiece new_contents = "Goodbye"; @@ -389,6 +397,7 @@ TEST_P(SharedMemoryTest, GetReadOnlyHandle) { EXPECT_EQ(new_contents, StringPiece(static_cast<const char*>(writable_shmem.memory()), new_contents.size())); +#endif // 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 @@ -594,6 +603,29 @@ TEST_P(SharedMemoryTest, AnonymousExecutable) { } #endif // !defined(OS_IOS) +#if defined(OS_ANDROID) +// This test is restricted to Android since there is no way on other platforms +// to guarantee that a region can never be mapped with PROT_EXEC. E.g. on +// Linux, anonymous shared regions come from /dev/shm which can be mounted +// without 'noexec'. In this case, anything can perform an mprotect() to +// change the protection mask of a given page. +TEST(SharedMemoryTest, AnonymousIsNotExecutableByDefault) { + const uint32_t kTestSize = 1 << 16; + + SharedMemory shared_memory; + SharedMemoryCreateOptions options; + options.size = kTestSize; + + EXPECT_TRUE(shared_memory.Create(options)); + EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); + + errno = 0; + EXPECT_EQ(-1, mprotect(shared_memory.memory(), shared_memory.requested_size(), + PROT_READ | PROT_EXEC)); + EXPECT_EQ(EACCES, errno); +} +#endif // OS_ANDROID + // Android supports a different permission model than POSIX for its "ashmem" // shared memory implementation. So the tests about file permissions are not // included on Android. Fuchsia does not use a file-backed shared memory @@ -844,4 +876,86 @@ INSTANTIATE_TEST_CASE_P(SkipDevShm, ::testing::Values(Mode::DisableDevShm)); #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) +#if defined(OS_ANDROID) +TEST(SharedMemoryTest, ReadOnlyRegions) { + const uint32_t kDataSize = 1024; + SharedMemory memory; + SharedMemoryCreateOptions options; + options.size = kDataSize; + EXPECT_TRUE(memory.Create(options)); + + EXPECT_FALSE(memory.handle().IsRegionReadOnly()); + + // Check that it is possible to map the region directly from the fd. + int region_fd = memory.handle().GetHandle(); + EXPECT_GE(region_fd, 0); + void* address = mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, + region_fd, 0); + bool success = address && address != MAP_FAILED; + ASSERT_TRUE(address); + ASSERT_NE(address, MAP_FAILED); + if (success) { + EXPECT_EQ(0, munmap(address, kDataSize)); + } + + ASSERT_TRUE(memory.handle().SetRegionReadOnly()); + EXPECT_TRUE(memory.handle().IsRegionReadOnly()); + + // Check that it is no longer possible to map the region read/write. + errno = 0; + address = mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, + region_fd, 0); + success = address && address != MAP_FAILED; + ASSERT_FALSE(success); + ASSERT_EQ(EPERM, errno); + if (success) { + EXPECT_EQ(0, munmap(address, kDataSize)); + } +} + +TEST(SharedMemoryTest, ReadOnlyDescriptors) { + const uint32_t kDataSize = 1024; + SharedMemory memory; + SharedMemoryCreateOptions options; + options.size = kDataSize; + EXPECT_TRUE(memory.Create(options)); + + EXPECT_FALSE(memory.handle().IsRegionReadOnly()); + + // Getting a read-only descriptor should not make the region read-only itself. + SharedMemoryHandle ro_handle = memory.GetReadOnlyHandle(); + EXPECT_FALSE(memory.handle().IsRegionReadOnly()); + + // Mapping a writable region from a read-only descriptor should not + // be possible, it will DCHECK() in debug builds (see test below), + // while returning false on release ones. + { + bool dcheck_fired = false; + logging::ScopedLogAssertHandler log_assert( + base::BindRepeating([](bool* flag, const char*, int, base::StringPiece, + base::StringPiece) { *flag = true; }, + base::Unretained(&dcheck_fired))); + + SharedMemory rw_region(ro_handle.Duplicate(), /* read_only */ false); + EXPECT_FALSE(rw_region.Map(kDataSize)); + EXPECT_EQ(DCHECK_IS_ON() ? true : false, dcheck_fired); + } + + // Nor shall it turn the region read-only itself. + EXPECT_FALSE(ro_handle.IsRegionReadOnly()); + + // Mapping a read-only region from a read-only descriptor should work. + SharedMemory ro_region(ro_handle.Duplicate(), /* read_only */ true); + EXPECT_TRUE(ro_region.Map(kDataSize)); + + // And it should turn the region read-only too. + EXPECT_TRUE(ro_handle.IsRegionReadOnly()); + EXPECT_TRUE(memory.handle().IsRegionReadOnly()); + EXPECT_FALSE(memory.Map(kDataSize)); + + ro_handle.Close(); +} + +#endif // OS_ANDROID + } // namespace base diff --git a/chromium/base/metrics/field_trial.cc b/chromium/base/metrics/field_trial.cc index 7f7b372da00..0214f5a876c 100644 --- a/chromium/base/metrics/field_trial.cc +++ b/chromium/base/metrics/field_trial.cc @@ -229,7 +229,20 @@ bool DeserializeGUIDFromStringPieces(base::StringPiece first, *guid = base::UnguessableToken::Deserialize(high, low); return true; } -#endif + +// Extract a read-only SharedMemoryHandle from an existing |shared_memory| +// handle. Note that on Android, this also makes the whole region read-only. +SharedMemoryHandle GetSharedMemoryReadOnlyHandle(SharedMemory* shared_memory) { + SharedMemoryHandle result = shared_memory->GetReadOnlyHandle(); +#if defined(OS_ANDROID) + // On Android, turn the region read-only. This prevents any future + // writable mapping attempts, but the original one in |shm| survives + // and is still usable in the current process. + result.SetRegionReadOnly(); +#endif // OS_ANDROID + return result; +} +#endif // !OS_NACL } // namespace @@ -1306,10 +1319,8 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { global_->field_trial_allocator_.get()); #if !defined(OS_NACL) - // Set |readonly_allocator_handle_| so we can pass it to be inherited and - // via the command line. - global_->readonly_allocator_handle_ = - global_->field_trial_allocator_->shared_memory()->GetReadOnlyHandle(); + global_->readonly_allocator_handle_ = GetSharedMemoryReadOnlyHandle( + global_->field_trial_allocator_->shared_memory()); #endif } diff --git a/chromium/base/metrics/field_trial.h b/chromium/base/metrics/field_trial.h index f794803f315..c58666ce255 100644 --- a/chromium/base/metrics/field_trial.h +++ b/chromium/base/metrics/field_trial.h @@ -650,6 +650,7 @@ class BASE_EXPORT FieldTrialList { FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory); FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, SerializeSharedMemoryHandleMetadata); + FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryHandle); // Serialization is used to pass information about the handle to child // processes. It passes a reference to the relevant OS resource, and it passes diff --git a/chromium/base/metrics/field_trial_unittest.cc b/chromium/base/metrics/field_trial_unittest.cc index 56f727840d2..406f5616664 100644 --- a/chromium/base/metrics/field_trial_unittest.cc +++ b/chromium/base/metrics/field_trial_unittest.cc @@ -20,6 +20,8 @@ #include "base/test/gtest_util.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_shared_memory_util.h" +#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -75,7 +77,7 @@ class TestFieldTrialObserver : public FieldTrialList::Observer { } // namespace -class FieldTrialTest : public testing::Test { +class FieldTrialTest : public ::testing::Test { public: FieldTrialTest() : trial_list_(nullptr) {} @@ -1383,4 +1385,25 @@ TEST(FieldTrialListTest, SerializeSharedMemoryHandleMetadata) { } #endif // !defined(OS_NACL) +// Verify that the field trial shared memory handle is really read-only, and +// does not allow writable mappings. Test disabled on NaCl, Windows and Fuchsia +// which don't support/implement GetFieldTrialHandle(). For Fuchsia, see +// crbug.com/752368 +#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA) +TEST(FieldTrialListTest, CheckReadOnlySharedMemoryHandle) { + FieldTrialList field_trial_list(nullptr); + FieldTrialList::CreateFieldTrial("Trial1", "Group1"); + + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + + FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); + + SharedMemoryHandle handle = FieldTrialList::GetFieldTrialHandle(); + ASSERT_TRUE(handle.IsValid()); + + ASSERT_TRUE(CheckReadOnlySharedMemoryHandleForTesting(handle)); +} +#endif // !OS_NACL && !OS_WIN && !OS_FUCHSIA + } // namespace base diff --git a/chromium/base/test/BUILD.gn b/chromium/base/test/BUILD.gn index e260022971a..e6e7752aa8b 100644 --- a/chromium/base/test/BUILD.gn +++ b/chromium/base/test/BUILD.gn @@ -117,6 +117,8 @@ static_library("test_support") { "test_pending_task.h", "test_reg_util_win.cc", "test_reg_util_win.h", + "test_shared_memory_util.cc", + "test_shared_memory_util.h", "test_shortcut_win.cc", "test_shortcut_win.h", "test_simple_task_runner.cc", |