123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- // Copyright (c) 2021 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/allocator/partition_allocator/tagging.h"
- #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
- #include "base/allocator/partition_allocator/partition_alloc_base/cpu.h"
- #include "base/allocator/partition_allocator/partition_alloc_check.h"
- #include "base/allocator/partition_allocator/partition_alloc_config.h"
- #include "build/build_config.h"
- #if defined(PA_HAS_MEMORY_TAGGING)
- #include <arm_acle.h>
- #include <sys/auxv.h>
- #include <sys/prctl.h>
- #define PR_SET_TAGGED_ADDR_CTRL 55
- #define PR_GET_TAGGED_ADDR_CTRL 56
- #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
- #if BUILDFLAG(IS_LINUX)
- #include <linux/version.h>
- // Linux headers already provide these since v5.10.
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
- #define HAS_PR_MTE_MACROS
- #endif
- #endif
- #ifndef HAS_PR_MTE_MACROS
- #define PR_MTE_TCF_SHIFT 1
- #define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
- #define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
- #define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
- #define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
- #define PR_MTE_TAG_SHIFT 3
- #define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
- #endif
- #endif
- #if BUILDFLAG(IS_ANDROID)
- #include "base/allocator/partition_allocator/partition_alloc_base/files/file_path.h"
- #include "base/allocator/partition_allocator/partition_alloc_base/native_library.h"
- #endif // BUILDFLAG(IS_ANDROID)
- namespace partition_alloc {
- #if defined(PA_HAS_MEMORY_TAGGING)
- namespace {
- void ChangeMemoryTaggingModeInternal(unsigned prctl_mask) {
- if (internal::base::CPU::GetInstanceNoAllocation().has_mte()) {
- int status = prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_mask, 0, 0, 0);
- PA_CHECK(status == 0);
- }
- }
- } // namespace
- #endif // defined(PA_HAS_MEMORY_TAGGING)
- void ChangeMemoryTaggingModeForCurrentThread(TagViolationReportingMode m) {
- #if defined(PA_HAS_MEMORY_TAGGING)
- if (m == TagViolationReportingMode::kSynchronous) {
- ChangeMemoryTaggingModeInternal(PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
- (0xfffe << PR_MTE_TAG_SHIFT));
- } else if (m == TagViolationReportingMode::kAsynchronous) {
- ChangeMemoryTaggingModeInternal(PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC |
- (0xfffe << PR_MTE_TAG_SHIFT));
- } else {
- ChangeMemoryTaggingModeInternal(PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_NONE);
- }
- #endif // defined(PA_HAS_MEMORY_TAGGING)
- }
- namespace internal {
- #if BUILDFLAG(IS_ANDROID)
- void ChangeMemoryTaggingModeForAllThreadsPerProcess(
- TagViolationReportingMode m) {
- #if defined(PA_HAS_MEMORY_TAGGING)
- // In order to support Android NDK API level below 26, we need to call
- // mallopt via dynamic linker.
- // int mallopt(int param, int value);
- using MalloptSignature = int (*)(int, int);
- static MalloptSignature mallopt_fnptr = []() {
- base::FilePath module_path;
- base::NativeLibraryLoadError load_error;
- base::FilePath library_path = module_path.Append("libc.so");
- base::NativeLibrary library =
- base::LoadNativeLibrary(library_path, &load_error);
- PA_CHECK(library);
- void* func_ptr =
- base::GetFunctionPointerFromNativeLibrary(library, "mallopt");
- PA_CHECK(func_ptr);
- return reinterpret_cast<MalloptSignature>(func_ptr);
- }();
- int status = 0;
- if (m == TagViolationReportingMode::kSynchronous) {
- status = mallopt_fnptr(M_BIONIC_SET_HEAP_TAGGING_LEVEL,
- M_HEAP_TAGGING_LEVEL_SYNC);
- } else if (m == TagViolationReportingMode::kAsynchronous) {
- status = mallopt_fnptr(M_BIONIC_SET_HEAP_TAGGING_LEVEL,
- M_HEAP_TAGGING_LEVEL_ASYNC);
- } else {
- status = mallopt_fnptr(M_BIONIC_SET_HEAP_TAGGING_LEVEL,
- M_HEAP_TAGGING_LEVEL_NONE);
- }
- PA_CHECK(status);
- #endif // defined(PA_HAS_MEMORY_TAGGING)
- }
- #endif // BUILDFLAG(IS_ANDROID)
- namespace {
- [[maybe_unused]] static bool CheckTagRegionParameters(void* ptr, size_t sz) {
- // Check that ptr and size are correct for MTE
- uintptr_t ptr_as_uint = reinterpret_cast<uintptr_t>(ptr);
- bool ret = (ptr_as_uint % kMemTagGranuleSize == 0) &&
- (sz % kMemTagGranuleSize == 0) && sz;
- return ret;
- }
- #if defined(PA_HAS_MEMORY_TAGGING)
- static bool HasCPUMemoryTaggingExtension() {
- return base::CPU::GetInstanceNoAllocation().has_mte();
- }
- #endif // defined(PA_HAS_MEMORY_TAGGING)
- #if defined(PA_HAS_MEMORY_TAGGING)
- void* TagRegionRandomlyForMTE(void* ptr, size_t sz, uint64_t mask) {
- // Randomly tag a region (MTE-enabled systems only). The first 16-byte
- // granule is randomly tagged, all other granules in the region are
- // then assigned that initial tag via __arm_mte_set_tag.
- if (!CheckTagRegionParameters(ptr, sz))
- return nullptr;
- // __arm_mte_create_random_tag generates a randomly tagged pointer via the
- // hardware's random number generator, but does not apply it to the memory.
- char* nptr = reinterpret_cast<char*>(__arm_mte_create_random_tag(ptr, mask));
- for (size_t i = 0; i < sz; i += kMemTagGranuleSize) {
- // Next, tag the first and all subsequent granules with the randomly tag.
- __arm_mte_set_tag(nptr +
- i); // Tag is taken from the top bits of the argument.
- }
- return nptr;
- }
- void* TagRegionIncrementForMTE(void* ptr, size_t sz) {
- // Increment a region's tag (MTE-enabled systems only), using the tag of the
- // first granule.
- if (!CheckTagRegionParameters(ptr, sz))
- return nullptr;
- // Increment ptr's tag.
- char* nptr = reinterpret_cast<char*>(__arm_mte_increment_tag(ptr, 1u));
- for (size_t i = 0; i < sz; i += kMemTagGranuleSize) {
- // Apply the tag to the first granule, and all subsequent granules.
- __arm_mte_set_tag(nptr + i);
- }
- return nptr;
- }
- void* RemaskVoidPtrForMTE(void* ptr) {
- if (PA_LIKELY(ptr)) {
- // Can't look up the tag for a null ptr (segfaults).
- return __arm_mte_get_tag(ptr);
- }
- return nullptr;
- }
- #endif
- void* TagRegionIncrementNoOp(void* ptr, size_t sz) {
- // Region parameters are checked even on non-MTE systems to check the
- // intrinsics are used correctly.
- return ptr;
- }
- void* TagRegionRandomlyNoOp(void* ptr, size_t sz, uint64_t mask) {
- // Verifies a 16-byte aligned tagging granule, size tagging granule (all
- // architectures).
- return ptr;
- }
- void* RemaskVoidPtrNoOp(void* ptr) {
- return ptr;
- }
- } // namespace
- void InitializeMTESupportIfNeeded() {
- #if defined(PA_HAS_MEMORY_TAGGING)
- if (HasCPUMemoryTaggingExtension()) {
- global_remask_void_ptr_fn = RemaskVoidPtrForMTE;
- global_tag_memory_range_increment_fn = TagRegionIncrementForMTE;
- global_tag_memory_range_randomly_fn = TagRegionRandomlyForMTE;
- }
- #endif
- }
- RemaskPtrInternalFn* global_remask_void_ptr_fn = RemaskVoidPtrNoOp;
- TagMemoryRangeIncrementInternalFn* global_tag_memory_range_increment_fn =
- TagRegionIncrementNoOp;
- TagMemoryRangeRandomlyInternalFn* global_tag_memory_range_randomly_fn =
- TagRegionRandomlyNoOp;
- TagViolationReportingMode GetMemoryTaggingModeForCurrentThread() {
- #if defined(PA_HAS_MEMORY_TAGGING)
- base::CPU cpu;
- if (!cpu.has_mte()) {
- return TagViolationReportingMode::kUndefined;
- }
- int status = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
- PA_CHECK(status >= 0);
- if ((status & PR_TAGGED_ADDR_ENABLE) && (status & PR_MTE_TCF_SYNC)) {
- return TagViolationReportingMode::kSynchronous;
- }
- if ((status & PR_TAGGED_ADDR_ENABLE) && (status & PR_MTE_TCF_ASYNC)) {
- return TagViolationReportingMode::kAsynchronous;
- }
- #endif // defined(PA_HAS_MEMORY_TAGGING)
- return TagViolationReportingMode::kUndefined;
- }
- } // namespace internal
- } // namespace partition_alloc
|