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