Commit 8ea8955c authored by Vlad Tsyrklevich's avatar Vlad Tsyrklevich Committed by Commit Bot

Deprecate base::ProtectedMemory

base::ProtectedMemory is being deprecated because it's not widely used
enough to make a security impact and justify its maintenance burden.
All uses of base::ProtectedMemory have already been removed, now delete
the remaining code and build changes.

Bug: 1018834, 1007916
Change-Id: I2df8d6d30d3ccfa7e8fb679d047e9df02539ff49
Fixes: 1018834, 1007916
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1891114
Auto-Submit: Vlad Tsyrklevich <vtsyrklevich@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Commit-Queue: Nico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711546}
parent 71235c3f
......@@ -318,9 +318,6 @@ jumbo_component("base") {
"memory/memory_pressure_monitor.h",
"memory/platform_shared_memory_region.cc",
"memory/platform_shared_memory_region.h",
"memory/protected_memory.cc",
"memory/protected_memory.h",
"memory/protected_memory_cfi.h",
"memory/ptr_util.h",
"memory/raw_scoped_refptr_mismatch_checker.h",
"memory/read_only_shared_memory_region.cc",
......@@ -897,7 +894,6 @@ jumbo_component("base") {
"memory/madv_free_discardable_memory_allocator_posix.h",
"memory/madv_free_discardable_memory_posix.cc",
"memory/madv_free_discardable_memory_posix.h",
"memory/protected_memory_posix.cc",
"message_loop/watchable_io_message_pump_posix.cc",
"message_loop/watchable_io_message_pump_posix.h",
"native_library_posix.cc",
......@@ -964,7 +960,6 @@ jumbo_component("base") {
"files/memory_mapped_file_win.cc",
"logging_win.cc",
"logging_win.h",
"memory/protected_memory_win.cc",
"message_loop/message_pump_win.cc",
"message_loop/message_pump_win.h",
"native_library_win.cc",
......@@ -1323,7 +1318,6 @@ jumbo_component("base") {
":logging_buildflags",
":orderfile_buildflags",
":partition_alloc_buildflags",
":protected_memory_buildflags",
":sanitizer_buildflags",
":synchronization_buildflags",
"//base/numerics:base_numerics",
......@@ -1586,7 +1580,6 @@ jumbo_component("base") {
"fuchsia/startup_context.cc",
"fuchsia/startup_context.h",
"memory/platform_shared_memory_region_fuchsia.cc",
"memory/protected_memory_posix.cc",
"memory/shared_memory_fuchsia.cc",
"memory/shared_memory_handle_fuchsia.cc",
"message_loop/message_pump_fuchsia.cc",
......@@ -2153,15 +2146,6 @@ buildflag_header("orderfile_buildflags") {
]
}
# Build flags for ProtectedMemory, temporary workaround for crbug.com/792777
# TODO(vtsyrklevich): Remove once support for gold on Android/CrOs is dropped
buildflag_header("protected_memory_buildflags") {
header = "protected_memory_buildflags.h"
header_dir = "base/memory"
flags = [ "USE_LLD=$use_lld" ]
}
buildflag_header("synchronization_buildflags") {
header = "synchronization_buildflags.h"
header_dir = "base/synchronization"
......@@ -2604,7 +2588,6 @@ test("base_unittests") {
"memory/memory_pressure_listener_unittest.cc",
"memory/memory_pressure_monitor_unittest.cc",
"memory/platform_shared_memory_region_unittest.cc",
"memory/protected_memory_unittest.cc",
"memory/ptr_util_unittest.cc",
"memory/ref_counted_memory_unittest.cc",
"memory/ref_counted_unittest.cc",
......
// Copyright 2017 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.
#include "base/memory/protected_memory.h"
#include "base/synchronization/lock.h"
namespace base {
#if !defined(COMPONENT_BUILD)
PROTECTED_MEMORY_SECTION int AutoWritableMemory::writers = 0;
#endif // !defined(COMPONENT_BUILD)
base::LazyInstance<Lock>::Leaky AutoWritableMemory::writers_lock =
LAZY_INSTANCE_INITIALIZER;
} // namespace base
This diff is collapsed.
// Copyright 2017 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.
// Helper routines to call function pointers stored in protected memory with
// Control Flow Integrity indirect call checking disabled. Some indirect calls,
// e.g. dynamically resolved symbols in another DSO, can not be accounted for by
// CFI-icall. These routines allow those symbols to be called without CFI-icall
// checking safely by ensuring that they are placed in protected memory.
#ifndef BASE_MEMORY_PROTECTED_MEMORY_CFI_H_
#define BASE_MEMORY_PROTECTED_MEMORY_CFI_H_
#include <utility>
#include "base/cfi_buildflags.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/protected_memory.h"
#include "build/build_config.h"
#if BUILDFLAG(CFI_ICALL_CHECK) && !PROTECTED_MEMORY_ENABLED
#error "CFI-icall enabled for platform without protected memory support"
#endif // BUILDFLAG(CFI_ICALL_CHECK) && !PROTECTED_MEMORY_ENABLED
namespace base {
namespace internal {
// This class is used to exempt calls to function pointers stored in
// ProtectedMemory from cfi-icall checking. It's not secure to use directly, it
// should only be used by the UnsanitizedCfiCall() functions below. Given an
// UnsanitizedCfiCall object, you can use operator() to call the encapsulated
// function pointer without cfi-icall checking.
template <typename FunctionType>
class UnsanitizedCfiCall {
public:
explicit UnsanitizedCfiCall(FunctionType function) : function_(function) {}
UnsanitizedCfiCall(UnsanitizedCfiCall&&) = default;
template <typename... Args>
NO_SANITIZE("cfi-icall")
auto operator()(Args&&... args) {
return function_(std::forward<Args>(args)...);
}
private:
FunctionType function_;
DISALLOW_IMPLICIT_CONSTRUCTORS(UnsanitizedCfiCall);
};
} // namespace internal
// These functions can be used to call function pointers in ProtectedMemory
// without cfi-icall checking. They are intended to be used to create an
// UnsanitizedCfiCall object and immediately call it. UnsanitizedCfiCall objects
// should not initialized directly or stored because they hold a function
// pointer that will be called without CFI-icall checking in mutable memory. The
// functions can be used as shown below:
// ProtectedMemory<void (*)(int)> p;
// UnsanitizedCfiCall(p)(5); /* In place of (*p)(5); */
template <typename T>
auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM) {
#if PROTECTED_MEMORY_ENABLED
DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd)
<< "ProtectedMemoryStart=" << ProtectedMemoryStart << ", &PM=" << &PM
<< ", ProtectedMemoryEnd=" << ProtectedMemoryEnd;
#endif // PROTECTED_MEMORY_ENABLED
return internal::UnsanitizedCfiCall<T>(*PM);
}
// struct S { void (*fp)(int); } s;
// ProtectedMemory<S> p;
// UnsanitizedCfiCall(p, &S::fp)(5); /* In place of p->fp(5); */
template <typename T, typename Member>
auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM, Member member) {
#if PROTECTED_MEMORY_ENABLED
DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd)
<< "ProtectedMemoryStart=" << ProtectedMemoryStart << ", &PM=" << &PM
<< ", ProtectedMemoryEnd=" << ProtectedMemoryEnd;
#endif // PROTECTED_MEMORY_ENABLED
return internal::UnsanitizedCfiCall<decltype(*PM.*member)>(*PM.*member);
}
} // namespace base
#endif // BASE_MEMORY_PROTECTED_MEMORY_CFI_H_
// Copyright 2017 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.
#include "base/memory/protected_memory.h"
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#if defined(OS_LINUX)
#include <sys/resource.h>
#endif // defined(OS_LINUX)
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach.h>
#include <mach/mach_vm.h>
#endif // defined(OS_MACOSX) && !defined(OS_IOS)
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
namespace base {
namespace {
bool SetMemory(void* start, void* end, int prot) {
DCHECK(end > start);
const uintptr_t page_mask = ~(base::GetPageSize() - 1);
const uintptr_t page_start = reinterpret_cast<uintptr_t>(start) & page_mask;
return mprotect(reinterpret_cast<void*>(page_start),
reinterpret_cast<uintptr_t>(end) - page_start, prot) == 0;
}
} // namespace
bool AutoWritableMemory::SetMemoryReadWrite(void* start, void* end) {
return SetMemory(start, end, PROT_READ | PROT_WRITE);
}
bool AutoWritableMemory::SetMemoryReadOnly(void* start, void* end) {
return SetMemory(start, end, PROT_READ);
}
#if defined(OS_LINUX)
void AssertMemoryIsReadOnly(const void* ptr) {
#if DCHECK_IS_ON()
const uintptr_t page_mask = ~(base::GetPageSize() - 1);
const uintptr_t page_start = reinterpret_cast<uintptr_t>(ptr) & page_mask;
// Note: We've casted away const here, which should not be meaningful since
// if the memory is written to we will abort immediately.
int result =
getrlimit(RLIMIT_NPROC, reinterpret_cast<struct rlimit*>(page_start));
DCHECK_EQ(result, -1);
DCHECK_EQ(errno, EFAULT);
#endif // DCHECK_IS_ON()
}
#elif defined(OS_MACOSX) && !defined(OS_IOS)
void AssertMemoryIsReadOnly(const void* ptr) {
#if DCHECK_IS_ON()
mach_port_t object_name;
vm_region_basic_info_64 region_info;
mach_vm_size_t size = 1;
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
kern_return_t kr = mach_vm_region(
mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&ptr), &size,
VM_REGION_BASIC_INFO_64, reinterpret_cast<vm_region_info_t>(&region_info),
&count, &object_name);
DCHECK_EQ(kr, KERN_SUCCESS);
DCHECK_EQ(region_info.protection, VM_PROT_READ);
#endif // DCHECK_IS_ON()
}
#endif // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
} // namespace base
// Copyright 2017 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.
#include "base/memory/protected_memory.h"
#include "base/cfi_buildflags.h"
#include "base/memory/protected_memory_cfi.h"
#include "base/synchronization/lock.h"
#include "base/test/gtest_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
struct Data {
Data() = default;
Data(int foo_) : foo(foo_) {}
int foo;
};
} // namespace
class ProtectedMemoryTest : public ::testing::Test {
protected:
// Run tests one at a time. Some of the negative tests can not be made thread
// safe.
void SetUp() final { lock.Acquire(); }
void TearDown() final { lock.Release(); }
Lock lock;
};
PROTECTED_MEMORY_SECTION ProtectedMemory<int> g_init;
TEST_F(ProtectedMemoryTest, Initializer) {
static ProtectedMemory<int>::Initializer I(&g_init, 4);
EXPECT_EQ(*g_init, 4);
}
PROTECTED_MEMORY_SECTION ProtectedMemory<Data> g_data;
TEST_F(ProtectedMemoryTest, Basic) {
AutoWritableMemory writer = AutoWritableMemory::Create(g_data);
g_data->foo = 5;
EXPECT_EQ(g_data->foo, 5);
}
#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
#if PROTECTED_MEMORY_ENABLED
TEST_F(ProtectedMemoryTest, ReadOnlyOnStart) {
EXPECT_DEATH(
{
g_data->foo = 6;
AutoWritableMemory::Create(g_data);
},
"");
}
TEST_F(ProtectedMemoryTest, ReadOnlyAfterSetWritable) {
{ AutoWritableMemory writer = AutoWritableMemory::Create(g_data); }
EXPECT_DEATH({ g_data->foo = 7; }, "");
}
TEST_F(ProtectedMemoryTest, AssertMemoryIsReadOnly) {
AssertMemoryIsReadOnly(&g_data->foo);
{ AutoWritableMemory::Create(g_data); }
AssertMemoryIsReadOnly(&g_data->foo);
ProtectedMemory<Data> writable_data;
EXPECT_DCHECK_DEATH({ AssertMemoryIsReadOnly(&writable_data->foo); });
}
TEST_F(ProtectedMemoryTest, FailsIfDefinedOutsideOfProtectMemoryRegion) {
ProtectedMemory<Data> data;
EXPECT_DCHECK_DEATH({ AutoWritableMemory::Create(data); });
}
TEST_F(ProtectedMemoryTest, UnsanitizedCfiCallOutsideOfProtectedMemoryRegion) {
ProtectedMemory<void (*)(void)> data;
EXPECT_DCHECK_DEATH({ UnsanitizedCfiCall(data)(); });
}
#endif // PROTECTED_MEMORY_ENABLED
namespace {
struct BadIcall {
BadIcall() = default;
BadIcall(int (*fp_)(int)) : fp(fp_) {}
int (*fp)(int);
};
unsigned int bad_icall(int i) {
return 4 + i;
}
} // namespace
PROTECTED_MEMORY_SECTION ProtectedMemory<BadIcall> icall_pm1;
TEST_F(ProtectedMemoryTest, BadMemberCall) {
static ProtectedMemory<BadIcall>::Initializer I(
&icall_pm1, BadIcall(reinterpret_cast<int (*)(int)>(&bad_icall)));
EXPECT_EQ(UnsanitizedCfiCall(icall_pm1, &BadIcall::fp)(1), 5);
#if !BUILDFLAG(CFI_ICALL_CHECK)
EXPECT_EQ(icall_pm1->fp(1), 5);
#elif BUILDFLAG(CFI_ENFORCEMENT_TRAP) || BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC)
EXPECT_DEATH({ icall_pm1->fp(1); }, "");
#endif
}
PROTECTED_MEMORY_SECTION ProtectedMemory<int (*)(int)> icall_pm2;
TEST_F(ProtectedMemoryTest, BadFnPtrCall) {
static ProtectedMemory<int (*)(int)>::Initializer I(
&icall_pm2, reinterpret_cast<int (*)(int)>(&bad_icall));
EXPECT_EQ(UnsanitizedCfiCall(icall_pm2)(1), 5);
#if !BUILDFLAG(CFI_ICALL_CHECK)
EXPECT_EQ((*icall_pm2)(1), 5);
#elif BUILDFLAG(CFI_ENFORCEMENT_TRAP) || BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC)
EXPECT_DEATH({ (*icall_pm2)(1); }, "");
#endif
}
#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
} // namespace base
// Copyright 2017 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.
#include "base/memory/protected_memory.h"
#include <windows.h>
#include <stdint.h>
#include "base/process/process_metrics.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
namespace base {
namespace {
bool SetMemory(void* start, void* end, DWORD prot) {
DCHECK(end > start);
const uintptr_t page_mask = ~(base::GetPageSize() - 1);
const uintptr_t page_start = reinterpret_cast<uintptr_t>(start) & page_mask;
DWORD old_prot;
return VirtualProtect(reinterpret_cast<void*>(page_start),
reinterpret_cast<uintptr_t>(end) - page_start, prot,
&old_prot) != 0;
}
} // namespace
bool AutoWritableMemory::SetMemoryReadWrite(void* start, void* end) {
return SetMemory(start, end, PAGE_READWRITE);
}
bool AutoWritableMemory::SetMemoryReadOnly(void* start, void* end) {
return SetMemory(start, end, PAGE_READONLY);
}
void AssertMemoryIsReadOnly(const void* ptr) {
#if DCHECK_IS_ON()
const uintptr_t page_mask = ~(base::GetPageSize() - 1);
const uintptr_t page_start = reinterpret_cast<uintptr_t>(ptr) & page_mask;
MEMORY_BASIC_INFORMATION info;
SIZE_T result =
VirtualQuery(reinterpret_cast<LPCVOID>(page_start), &info, sizeof(info));
DCHECK_GT(result, 0U);
DCHECK(info.Protect == PAGE_READONLY);
#endif // DCHECK_IS_ON()
}
} // namespace base
......@@ -40,15 +40,6 @@ config("compiler") {
ldflags = common_mac_flags
# Create a new read-only segment for protected memory. The default segments
# (__TEXT and __DATA) are mapped read-execute and read-write by default.
ldflags += [
"-segprot",
"PROTECTED_MEMORY",
"rw",
"r",
]
if (save_unstripped_output) {
ldflags += [ "-Wcrl,unstripped," + rebase_path(root_out_dir) ]
}
......
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