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