tagging.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (c) 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_TAGGING_H_
  5. #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_TAGGING_H_
  6. // This file contains method definitions to support Armv8.5-A's memory tagging
  7. // extension.
  8. #include <cstddef>
  9. #include <cstdint>
  10. #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
  11. #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
  12. #include "base/allocator/partition_allocator/partition_alloc_config.h"
  13. #include "build/build_config.h"
  14. namespace partition_alloc {
  15. // Enum configures Arm's MTE extension to operate in different modes
  16. enum class TagViolationReportingMode {
  17. // Default settings
  18. kUndefined,
  19. // MTE explicitly disabled.
  20. kDisabled,
  21. // Precise tag violation reports, higher overhead. Good for unittests
  22. // and security critical threads.
  23. kSynchronous,
  24. // Imprecise tag violation reports (async mode). Lower overhead.
  25. kAsynchronous,
  26. };
  27. // Changes the memory tagging mode for the calling thread.
  28. PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  29. void ChangeMemoryTaggingModeForCurrentThread(TagViolationReportingMode);
  30. namespace internal {
  31. constexpr int kMemTagGranuleSize = 16u;
  32. #if defined(PA_HAS_MEMORY_TAGGING)
  33. constexpr uint64_t kPtrTagMask = 0xff00000000000000uLL;
  34. #else
  35. constexpr uint64_t kPtrTagMask = 0;
  36. #endif // defined(PA_HAS_MEMORY_TAGGING)
  37. constexpr uint64_t kPtrUntagMask = ~kPtrTagMask;
  38. #if BUILDFLAG(IS_ANDROID)
  39. // Changes the memory tagging mode for all threads in the current process.
  40. PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  41. void ChangeMemoryTaggingModeForAllThreadsPerProcess(TagViolationReportingMode);
  42. #endif
  43. // Gets the memory tagging mode for the calling thread.
  44. PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  45. TagViolationReportingMode GetMemoryTaggingModeForCurrentThread();
  46. // Called by the partition allocator after initial startup, this detects MTE
  47. // support in the current CPU and replaces the active tagging intrinsics with
  48. // MTE versions if needed.
  49. PA_COMPONENT_EXPORT(PARTITION_ALLOC) void InitializeMTESupportIfNeeded();
  50. // These global function pointers hold the implementations of the tagging
  51. // intrinsics (TagMemoryRangeRandomly, TagMemoryRangeIncrement, RemaskPtr).
  52. // They are designed to be callable without taking a branch. They are initially
  53. // set to no-op functions in tagging.cc, but can be replaced with MTE-capable
  54. // ones through InitializeMTEIfNeeded(). This is conceptually similar to an
  55. // ifunc (but less secure) - we do it this way for now because the CrazyLinker
  56. // (needed for supporting old Android versions) doesn't support them. Initial
  57. // solution should be good enough for fuzzing/debug, ideally needs fixing for
  58. // async deployment on end-user devices.
  59. // TODO(bartekn): void* -> uintptr_t
  60. using RemaskPtrInternalFn = void*(void* ptr);
  61. using TagMemoryRangeIncrementInternalFn = void*(void* ptr, size_t size);
  62. using TagMemoryRangeRandomlyInternalFn = void*(void* ptr,
  63. size_t size,
  64. uint64_t mask);
  65. extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  66. TagMemoryRangeRandomlyInternalFn* global_tag_memory_range_randomly_fn;
  67. extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  68. TagMemoryRangeIncrementInternalFn* global_tag_memory_range_increment_fn;
  69. extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  70. RemaskPtrInternalFn* global_remask_void_ptr_fn;
  71. // Increments the tag of the memory range ptr. Useful for provable revocations
  72. // (e.g. free). Returns the pointer with the new tag. Ensures that the entire
  73. // range is set to the same tag.
  74. // TODO(bartekn): Remove the T* variant.
  75. // TODO(bartekn): Consider removing the return value.
  76. template <typename T>
  77. PA_ALWAYS_INLINE T* TagMemoryRangeIncrement(T* ptr, size_t size) {
  78. #if defined(PA_HAS_MEMORY_TAGGING)
  79. return reinterpret_cast<T*>(global_tag_memory_range_increment_fn(ptr, size));
  80. #else
  81. return ptr;
  82. #endif
  83. }
  84. PA_ALWAYS_INLINE void* TagMemoryRangeIncrement(uintptr_t ptr, size_t size) {
  85. return TagMemoryRangeIncrement(reinterpret_cast<void*>(ptr), size);
  86. }
  87. // Randomly changes the tag of the ptr memory range. Useful for initial random
  88. // initialization. Returns the pointer with the new tag. Ensures that the entire
  89. // range is set to the same tag.
  90. // TODO(bartekn): Remove the T* variant.
  91. template <typename T>
  92. PA_ALWAYS_INLINE T* TagMemoryRangeRandomly(T* ptr,
  93. size_t size,
  94. uint64_t mask = 0u) {
  95. #if defined(PA_HAS_MEMORY_TAGGING)
  96. return reinterpret_cast<T*>(
  97. global_tag_memory_range_randomly_fn(ptr, size, mask));
  98. #else
  99. return ptr;
  100. #endif
  101. }
  102. PA_ALWAYS_INLINE void* TagMemoryRangeRandomly(uintptr_t ptr,
  103. size_t size,
  104. uint64_t mask = 0u) {
  105. return TagMemoryRangeRandomly(reinterpret_cast<void*>(ptr), size, mask);
  106. }
  107. // Gets a version of ptr that's safe to dereference.
  108. template <typename T>
  109. PA_ALWAYS_INLINE T* TagPtr(T* ptr) {
  110. #if defined(PA_HAS_MEMORY_TAGGING)
  111. return reinterpret_cast<T*>(global_remask_void_ptr_fn(ptr));
  112. #else
  113. return ptr;
  114. #endif
  115. }
  116. // Gets a version of |address| that's safe to dereference, and casts to a
  117. // pointer.
  118. PA_ALWAYS_INLINE void* TagAddr(uintptr_t address) {
  119. return TagPtr(reinterpret_cast<void*>(address));
  120. }
  121. // Strips the tag bits off |address|.
  122. PA_ALWAYS_INLINE uintptr_t UntagAddr(uintptr_t address) {
  123. #if defined(PA_HAS_MEMORY_TAGGING)
  124. return address & internal::kPtrUntagMask;
  125. #else
  126. return address;
  127. #endif
  128. }
  129. } // namespace internal
  130. // Strips the tag bits off |ptr|.
  131. template <typename T>
  132. PA_ALWAYS_INLINE uintptr_t UntagPtr(T* ptr) {
  133. return internal::UntagAddr(reinterpret_cast<uintptr_t>(ptr));
  134. }
  135. } // namespace partition_alloc
  136. #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_TAGGING_H_