• 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_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