Commit e9cf4965 authored by Alexandr Ilin's avatar Alexandr Ilin Committed by Commit Bot

base/memory: Test mapping protection bits on all platforms

This CL adds a new MappingProtectionSetCorrectly test to the
PlatformSharedMemoryRegion. This test examines that page protection bits are
set correctly on a mapped region and that the process doesn't have rights to
change the protection level.

Bug: 795291
Change-Id: I029de3b31c74f7c14d92d5da7fb4a2a35ec7659a
Reviewed-on: https://chromium-review.googlesource.com/1199811Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Alexandr Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588506}
parent 5b4f4438
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "base/memory/platform_shared_memory_region.h" #include "base/memory/platform_shared_memory_region.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h" #include "base/memory/shared_memory.h"
#include "base/memory/shared_memory_mapping.h" #include "base/memory/shared_memory_mapping.h"
#include "base/process/process_metrics.h" #include "base/process/process_metrics.h"
...@@ -15,6 +16,16 @@ ...@@ -15,6 +16,16 @@
#if defined(OS_MACOSX) && !defined(OS_IOS) #if defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach_vm.h> #include <mach/mach_vm.h>
#include <sys/mman.h>
#elif defined(OS_POSIX) && !defined(OS_IOS)
#include <sys/mman.h>
#include "base/debug/proc_maps_linux.h"
#elif defined(OS_WIN)
#include <windows.h>
#elif defined(OS_FUCHSIA)
#include <lib/zx/object.h>
#include <lib/zx/process.h>
#include "base/fuchsia/fuchsia_logging.h"
#endif #endif
namespace base { namespace base {
...@@ -176,7 +187,8 @@ TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) { ...@@ -176,7 +187,8 @@ TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) {
EXPECT_FALSE(mapping.IsValid()); EXPECT_FALSE(mapping.IsValid());
} }
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX) #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
(!defined(OS_MACOSX) || defined(OS_IOS))
// Tests that the second handle is closed after a conversion to read-only on // Tests that the second handle is closed after a conversion to read-only on
// POSIX. // POSIX.
TEST_F(PlatformSharedMemoryRegionTest, TEST_F(PlatformSharedMemoryRegionTest,
...@@ -201,27 +213,77 @@ TEST_F(PlatformSharedMemoryRegionTest, ConvertToUnsafeInvalidatesSecondHandle) { ...@@ -201,27 +213,77 @@ TEST_F(PlatformSharedMemoryRegionTest, ConvertToUnsafeInvalidatesSecondHandle) {
} }
#endif #endif
void CheckReadOnlyMapProtection(void* addr) {
#if defined(OS_MACOSX) && !defined(OS_IOS) #if defined(OS_MACOSX) && !defined(OS_IOS)
// Tests that protection bits are set correctly for read-only region on MacOS.
TEST_F(PlatformSharedMemoryRegionTest, MapCurrentAndMaxProtectionSetCorrectly) {
PlatformSharedMemoryRegion region =
PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
ASSERT_TRUE(region.IsValid());
ASSERT_TRUE(region.ConvertToReadOnly());
WritableSharedMemoryMapping ro_mapping = MapForTesting(&region);
ASSERT_TRUE(ro_mapping.IsValid());
vm_region_basic_info_64 basic_info; vm_region_basic_info_64 basic_info;
mach_vm_size_t dummy_size = 0; mach_vm_size_t dummy_size = 0;
void* temp_addr = ro_mapping.memory(); void* temp_addr = addr;
MachVMRegionResult result = GetBasicInfo( MachVMRegionResult result = GetBasicInfo(
mach_task_self(), &dummy_size, mach_task_self(), &dummy_size,
reinterpret_cast<mach_vm_address_t*>(&temp_addr), &basic_info); reinterpret_cast<mach_vm_address_t*>(&temp_addr), &basic_info);
EXPECT_EQ(result, MachVMRegionResult::Success); ASSERT_EQ(result, MachVMRegionResult::Success);
EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ); EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ);
EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ); EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ);
#elif defined(OS_POSIX) && !defined(OS_IOS)
std::string proc_maps;
ASSERT_TRUE(base::debug::ReadProcMaps(&proc_maps));
std::vector<base::debug::MappedMemoryRegion> regions;
ASSERT_TRUE(base::debug::ParseProcMaps(proc_maps, &regions));
auto it =
std::find_if(regions.begin(), regions.end(),
[addr](const base::debug::MappedMemoryRegion& region) {
return region.start == reinterpret_cast<uintptr_t>(addr);
});
ASSERT_TRUE(it != regions.end());
EXPECT_EQ(it->permissions, base::debug::MappedMemoryRegion::READ);
#elif defined(OS_WIN)
MEMORY_BASIC_INFORMATION memory_info;
size_t result = VirtualQueryEx(GetCurrentProcess(), addr, &memory_info,
sizeof(memory_info));
ASSERT_GT(result, 0ULL) << "Failed executing VirtualQueryEx "
<< logging::SystemErrorCodeToString(
logging::GetLastSystemErrorCode());
EXPECT_EQ(memory_info.AllocationProtect, static_cast<DWORD>(PAGE_READONLY));
EXPECT_EQ(memory_info.Protect, static_cast<DWORD>(PAGE_READONLY));
#elif defined(OS_FUCHSIA)
// TODO(alexilin): We cannot call zx_object_get_info ZX_INFO_PROCESS_MAPS in
// this process. Consider to create an auxiliary process that will read the
// test process maps.
#endif
} }
bool TryToRestoreWritablePermissions(void* addr, size_t len) {
#if defined(OS_POSIX) && !defined(OS_IOS)
int result = mprotect(addr, len, PROT_READ | PROT_WRITE);
return result != -1;
#elif defined(OS_WIN)
DWORD old_protection;
return VirtualProtect(addr, len, PAGE_READWRITE, &old_protection);
#elif defined(OS_FUCHSIA)
zx_status_t status = zx::vmar::root_self()->protect(
reinterpret_cast<uintptr_t>(addr), len,
ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE);
return status == ZX_OK;
#else
return false;
#endif #endif
}
// Tests that protection bits are set correctly for read-only region.
TEST_F(PlatformSharedMemoryRegionTest, MappingProtectionSetCorrectly) {
PlatformSharedMemoryRegion region =
PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
ASSERT_TRUE(region.IsValid());
ASSERT_TRUE(region.ConvertToReadOnly());
WritableSharedMemoryMapping ro_mapping = MapForTesting(&region);
ASSERT_TRUE(ro_mapping.IsValid());
CheckReadOnlyMapProtection(ro_mapping.memory());
EXPECT_FALSE(TryToRestoreWritablePermissions(ro_mapping.memory(),
ro_mapping.mapped_size()));
CheckReadOnlyMapProtection(ro_mapping.memory());
}
// Tests that platform handle permissions are checked correctly. // Tests that platform handle permissions are checked correctly.
TEST_F(PlatformSharedMemoryRegionTest, TEST_F(PlatformSharedMemoryRegionTest,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment