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_SRC_PARTITION_ALLOC_TAGGING_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_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 "build/build_config.h"
15 #include "partition_alloc/partition_alloc_base/compiler_specific.h"
16 #include "partition_alloc/partition_alloc_base/component_export.h"
17 #include "partition_alloc/partition_alloc_config.h"
18
19 #if PA_CONFIG(HAS_MEMORY_TAGGING) && BUILDFLAG(IS_ANDROID)
20 #include <csignal>
21 #endif
22
23 namespace partition_alloc {
24
25 // Enum configures Arm's MTE extension to operate in different modes
26 enum class TagViolationReportingMode {
27 // Default settings
28 kUndefined,
29 // MTE explicitly disabled.
30 kDisabled,
31 // Precise tag violation reports, higher overhead. Good for unittests
32 // and security critical threads.
33 kSynchronous,
34 // Imprecise tag violation reports (async mode). Lower overhead.
35 kAsynchronous,
36 };
37
38 // Changes the memory tagging mode for the calling thread.
39 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
40 void ChangeMemoryTaggingModeForCurrentThread(TagViolationReportingMode);
41
42 namespace internal {
43
44 constexpr uint64_t kMemTagGranuleSize = 16u;
45 #if PA_CONFIG(HAS_MEMORY_TAGGING)
46 constexpr uint64_t kPtrTagMask = 0xff00000000000000uLL;
47 #else
48 constexpr uint64_t kPtrTagMask = 0;
49 #endif // PA_CONFIG(HAS_MEMORY_TAGGING)
50 constexpr uint64_t kPtrUntagMask = ~kPtrTagMask;
51
52 #if BUILDFLAG(IS_ANDROID)
53 // Changes the memory tagging mode for all threads in the current process.
54 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
55 void ChangeMemoryTaggingModeForAllThreadsPerProcess(TagViolationReportingMode);
56 #endif
57
58 // Gets the memory tagging mode for the calling thread. Returns kUndefined if
59 // MTE support is not available.
60 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
61 TagViolationReportingMode GetMemoryTaggingModeForCurrentThread();
62
63 // These forward-defined functions do not really exist in tagging.cc, they're
64 // resolved by the dynamic linker to MTE-capable versions on the right hardware.
65 #if PA_CONFIG(HAS_MEMORY_TAGGING)
66 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
67 void* TagMemoryRangeIncrementInternal(void* ptr, size_t size);
68 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
69 void* TagMemoryRangeRandomlyInternal(void* ptr, size_t size, uint64_t mask);
70 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
71 void* RemaskPointerInternal(void* ptr);
72 #endif
73
74 // Increments the tag of the memory range ptr. Useful for provable revocations
75 // (e.g. free). Returns the pointer with the new tag. Ensures that the entire
76 // range is set to the same tag.
TagMemoryRangeIncrement(void * ptr,size_t size)77 PA_ALWAYS_INLINE void* TagMemoryRangeIncrement(void* ptr, size_t size) {
78 #if PA_CONFIG(HAS_MEMORY_TAGGING)
79 return TagMemoryRangeIncrementInternal(ptr, size);
80 #else
81 return ptr;
82 #endif
83 }
84
TagMemoryRangeIncrement(uintptr_t address,size_t size)85 PA_ALWAYS_INLINE void* TagMemoryRangeIncrement(uintptr_t address, size_t size) {
86 return TagMemoryRangeIncrement(reinterpret_cast<void*>(address), size);
87 }
88
89 // Randomly changes the tag of the ptr memory range. Useful for initial random
90 // initialization. Returns the pointer with the new tag. Ensures that the entire
91 // range is set to the same tag.
92 PA_ALWAYS_INLINE void* TagMemoryRangeRandomly(uintptr_t address,
93 size_t size,
94 uint64_t mask = 0u) {
95 void* ptr = reinterpret_cast<void*>(address);
96 #if PA_CONFIG(HAS_MEMORY_TAGGING)
97 return reinterpret_cast<void*>(
98 TagMemoryRangeRandomlyInternal(ptr, size, mask));
99 #else
100 return ptr;
101 #endif
102 }
103
104 // Gets a version of ptr that's safe to dereference.
105 template <typename T>
TagPtr(T * ptr)106 PA_ALWAYS_INLINE T* TagPtr(T* ptr) {
107 #if PA_CONFIG(HAS_MEMORY_TAGGING)
108 return reinterpret_cast<T*>(RemaskPointerInternal(ptr));
109 #else
110 return ptr;
111 #endif
112 }
113
114 // Gets a version of |address| that's safe to dereference, and casts to a
115 // pointer.
TagAddr(uintptr_t address)116 PA_ALWAYS_INLINE void* TagAddr(uintptr_t address) {
117 return TagPtr(reinterpret_cast<void*>(address));
118 }
119
120 // Strips the tag bits off |address|.
UntagAddr(uintptr_t address)121 PA_ALWAYS_INLINE uintptr_t UntagAddr(uintptr_t address) {
122 #if PA_CONFIG(HAS_MEMORY_TAGGING)
123 return address & internal::kPtrUntagMask;
124 #else
125 return address;
126 #endif
127 }
128
129 } // namespace internal
130
131 // Strips the tag bits off |ptr|.
132 template <typename T>
UntagPtr(T * ptr)133 PA_ALWAYS_INLINE uintptr_t UntagPtr(T* ptr) {
134 return internal::UntagAddr(reinterpret_cast<uintptr_t>(ptr));
135 }
136
137 #if PA_CONFIG(HAS_MEMORY_TAGGING) && BUILDFLAG(IS_ANDROID)
PA_COMPONENT_EXPORT(PARTITION_ALLOC)138 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PermissiveMte {
139 public:
140 static void SetEnabled(bool enabled);
141 static bool HandleCrash(int signo, siginfo_t* siginfo, ucontext_t* context);
142
143 private:
144 static bool enabled_;
145 };
146 #endif
147
148 } // namespace partition_alloc
149
150 #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_TAGGING_H_
151