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