blob: 0c47f67a57416b0e847bb99d93ec05fdf4459344 [file] [log] [blame]
Dynamic Tools Team48429c72019-12-04 17:46:15 -08001//===-- memtag.h ------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef SCUDO_MEMTAG_H_
10#define SCUDO_MEMTAG_H_
11
12#include "internal_defs.h"
13
14#if SCUDO_LINUX
15#include <sys/auxv.h>
16#include <sys/prctl.h>
Dynamic Tools Team48429c72019-12-04 17:46:15 -080017#endif
18
19namespace scudo {
20
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -070021#if defined(__aarch64__) || defined(SCUDO_FUZZ)
Dynamic Tools Team48429c72019-12-04 17:46:15 -080022
Peter Collingbournecc3d4932020-12-21 18:39:03 -080023// We assume that Top-Byte Ignore is enabled if the architecture supports memory
24// tagging. Not all operating systems enable TBI, so we only claim architectural
25// support for memory tagging if the operating system enables TBI.
Peter Collingbourne6f816d12021-03-16 11:46:31 -070026#if SCUDO_LINUX && !defined(SCUDO_DISABLE_TBI)
Dynamic Tools Team48429c72019-12-04 17:46:15 -080027inline constexpr bool archSupportsMemoryTagging() { return true; }
Peter Collingbournecc3d4932020-12-21 18:39:03 -080028#else
29inline constexpr bool archSupportsMemoryTagging() { return false; }
30#endif
31
Dynamic Tools Team48429c72019-12-04 17:46:15 -080032inline constexpr uptr archMemoryTagGranuleSize() { return 16; }
33
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -070034inline uptr untagPointer(uptr Ptr) { return Ptr & ((1ULL << 56) - 1); }
35
Kostya Kortchinskya51a8922020-11-02 14:27:11 -080036inline uint8_t extractTag(uptr Ptr) { return (Ptr >> 56) & 0xf; }
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -070037
38#else
39
40inline constexpr bool archSupportsMemoryTagging() { return false; }
41
42inline uptr archMemoryTagGranuleSize() {
43 UNREACHABLE("memory tagging not supported");
44}
45
46inline uptr untagPointer(uptr Ptr) {
47 (void)Ptr;
48 UNREACHABLE("memory tagging not supported");
49}
50
51inline uint8_t extractTag(uptr Ptr) {
52 (void)Ptr;
53 UNREACHABLE("memory tagging not supported");
54}
55
56#endif
57
58#if defined(__aarch64__)
59
Roland McGrath2699c682021-01-05 11:55:11 -080060#if SCUDO_LINUX
61
Dynamic Tools Team48429c72019-12-04 17:46:15 -080062inline bool systemSupportsMemoryTagging() {
Peter Collingbourne9ece4092020-12-17 21:02:01 -080063#ifndef HWCAP2_MTE
64#define HWCAP2_MTE (1 << 18)
Dynamic Tools Team48429c72019-12-04 17:46:15 -080065#endif
Peter Collingbourne9ece4092020-12-17 21:02:01 -080066 return getauxval(AT_HWCAP2) & HWCAP2_MTE;
Dynamic Tools Team48429c72019-12-04 17:46:15 -080067}
68
69inline bool systemDetectsMemoryTagFaultsTestOnly() {
Vitaly Buka58be7da2021-05-27 10:10:50 -070070#ifndef PR_SET_TAGGED_ADDR_CTRL
71#define PR_SET_TAGGED_ADDR_CTRL 54
72#endif
Peter Collingbourne9ece4092020-12-17 21:02:01 -080073#ifndef PR_GET_TAGGED_ADDR_CTRL
74#define PR_GET_TAGGED_ADDR_CTRL 56
Dynamic Tools Team48429c72019-12-04 17:46:15 -080075#endif
Vitaly Buka58be7da2021-05-27 10:10:50 -070076#ifndef PR_TAGGED_ADDR_ENABLE
77#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
78#endif
Peter Collingbourne9ece4092020-12-17 21:02:01 -080079#ifndef PR_MTE_TCF_SHIFT
80#define PR_MTE_TCF_SHIFT 1
81#endif
Vitaly Buka58be7da2021-05-27 10:10:50 -070082#ifndef PR_MTE_TAG_SHIFT
83#define PR_MTE_TAG_SHIFT 3
84#endif
Peter Collingbourne9ece4092020-12-17 21:02:01 -080085#ifndef PR_MTE_TCF_NONE
86#define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
87#endif
Vitaly Buka58be7da2021-05-27 10:10:50 -070088#ifndef PR_MTE_TCF_SYNC
89#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
90#endif
Peter Collingbourne9ece4092020-12-17 21:02:01 -080091#ifndef PR_MTE_TCF_MASK
92#define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
93#endif
94 return (static_cast<unsigned long>(
95 prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &
96 PR_MTE_TCF_MASK) != PR_MTE_TCF_NONE;
Dynamic Tools Team48429c72019-12-04 17:46:15 -080097}
98
Vitaly Buka58be7da2021-05-27 10:10:50 -070099inline void enableSystemMemoryTaggingTestOnly() {
100 prctl(PR_SET_TAGGED_ADDR_CTRL,
101 PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT),
102 0, 0, 0);
103}
104
Roland McGrath2699c682021-01-05 11:55:11 -0800105#else // !SCUDO_LINUX
106
107inline bool systemSupportsMemoryTagging() { return false; }
108
Vitaly Buka58be7da2021-05-27 10:10:50 -0700109inline bool systemDetectsMemoryTagFaultsTestOnly() {
110 UNREACHABLE("memory tagging not supported");
111}
112
113inline void enableSystemMemoryTaggingTestOnly() {
114 UNREACHABLE("memory tagging not supported");
115}
Roland McGrath2699c682021-01-05 11:55:11 -0800116
117#endif // SCUDO_LINUX
118
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700119class ScopedDisableMemoryTagChecks {
Vitaly Bukaac28f8f2021-05-22 22:55:53 -0700120 uptr PrevTCO;
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700121
Kostya Kortchinskya51a8922020-11-02 14:27:11 -0800122public:
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700123 ScopedDisableMemoryTagChecks() {
Roland McGrath12ee7ad2021-04-13 15:03:54 -0700124 __asm__ __volatile__(
125 R"(
126 .arch_extension memtag
127 mrs %0, tco
128 msr tco, #1
129 )"
130 : "=r"(PrevTCO));
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700131 }
132
133 ~ScopedDisableMemoryTagChecks() {
Roland McGrath12ee7ad2021-04-13 15:03:54 -0700134 __asm__ __volatile__(
135 R"(
136 .arch_extension memtag
137 msr tco, %0
138 )"
139 :
140 : "r"(PrevTCO));
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700141 }
142};
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800143
Peter Collingbourne706ac402020-12-04 15:03:49 -0800144inline uptr selectRandomTag(uptr Ptr, uptr ExcludeMask) {
Vitaly Bukaef0e3542021-05-28 02:08:44 -0700145 ExcludeMask |= 1; // Always exclude Tag 0.
Peter Collingbourne706ac402020-12-04 15:03:49 -0800146 uptr TaggedPtr;
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800147 __asm__ __volatile__(
Roland McGrath12ee7ad2021-04-13 15:03:54 -0700148 R"(
149 .arch_extension memtag
150 irg %[TaggedPtr], %[Ptr], %[ExcludeMask]
151 )"
Peter Collingbourne706ac402020-12-04 15:03:49 -0800152 : [TaggedPtr] "=r"(TaggedPtr)
153 : [Ptr] "r"(Ptr), [ExcludeMask] "r"(ExcludeMask));
154 return TaggedPtr;
155}
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800156
Vitaly Buka98975bb2021-05-24 13:12:47 -0700157inline uptr addFixedTag(uptr Ptr, uptr Tag) {
158 DCHECK_LT(Tag, 16);
Vitaly Bukaecf52a72021-05-24 21:40:44 -0700159 DCHECK_EQ(untagPointer(Ptr), Ptr);
Vitaly Buka98975bb2021-05-24 13:12:47 -0700160 return Ptr | (Tag << 56);
161}
Peter Collingbournecc3d4932020-12-21 18:39:03 -0800162
Peter Collingbourne706ac402020-12-04 15:03:49 -0800163inline uptr storeTags(uptr Begin, uptr End) {
Vitaly Buka98975bb2021-05-24 13:12:47 -0700164 DCHECK_EQ(0, Begin % 16);
Peter Collingbourne71756e62021-04-20 14:53:41 -0700165 uptr LineSize, Next, Tmp;
166 __asm__ __volatile__(
167 R"(
168 .arch_extension memtag
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800169
Peter Collingbourne71756e62021-04-20 14:53:41 -0700170 // Compute the cache line size in bytes (DCZID_EL0 stores it as the log2
171 // of the number of 4-byte words) and bail out to the slow path if DCZID_EL0
172 // indicates that the DC instructions are unavailable.
173 DCZID .req %[Tmp]
174 mrs DCZID, dczid_el0
175 tbnz DCZID, #4, 3f
176 and DCZID, DCZID, #15
177 mov %[LineSize], #4
178 lsl %[LineSize], %[LineSize], DCZID
179 .unreq DCZID
180
181 // Our main loop doesn't handle the case where we don't need to perform any
182 // DC GZVA operations. If the size of our tagged region is less than
183 // twice the cache line size, bail out to the slow path since it's not
184 // guaranteed that we'll be able to do a DC GZVA.
185 Size .req %[Tmp]
186 sub Size, %[End], %[Cur]
187 cmp Size, %[LineSize], lsl #1
188 b.lt 3f
189 .unreq Size
190
191 LineMask .req %[Tmp]
192 sub LineMask, %[LineSize], #1
193
194 // STZG until the start of the next cache line.
195 orr %[Next], %[Cur], LineMask
196 1:
197 stzg %[Cur], [%[Cur]], #16
198 cmp %[Cur], %[Next]
199 b.lt 1b
200
201 // DC GZVA cache lines until we have no more full cache lines.
202 bic %[Next], %[End], LineMask
203 .unreq LineMask
204 2:
205 dc gzva, %[Cur]
206 add %[Cur], %[Cur], %[LineSize]
207 cmp %[Cur], %[Next]
208 b.lt 2b
209
210 // STZG until the end of the tagged region. This loop is also used to handle
211 // slow path cases.
212 3:
213 cmp %[Cur], %[End]
214 b.ge 4f
215 stzg %[Cur], [%[Cur]], #16
216 b 3b
217
218 4:
219 )"
220 : [Cur] "+&r"(Begin), [LineSize] "=&r"(LineSize), [Next] "=&r"(Next),
221 [Tmp] "=&r"(Tmp)
222 : [End] "r"(End)
223 : "memory");
Vitaly Buka98975bb2021-05-24 13:12:47 -0700224 DCHECK_EQ(0, Begin % 16);
Peter Collingbourne706ac402020-12-04 15:03:49 -0800225 return Begin;
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800226}
227
Peter Collingbourne34c88572021-04-20 14:54:32 -0700228inline void storeTag(uptr Ptr) {
Vitaly Buka98975bb2021-05-24 13:12:47 -0700229 DCHECK_EQ(0, Ptr % 16);
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800230 __asm__ __volatile__(R"(
Roland McGrath3c3951e2021-02-03 19:28:29 -0800231 .arch_extension memtag
Peter Collingbourne34c88572021-04-20 14:54:32 -0700232 stg %0, [%0]
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800233 )"
Peter Collingbourne34c88572021-04-20 14:54:32 -0700234 :
235 : "r"(Ptr)
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800236 : "memory");
237}
238
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800239inline uptr loadTag(uptr Ptr) {
Vitaly Buka98975bb2021-05-24 13:12:47 -0700240 DCHECK_EQ(0, Ptr % 16);
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800241 uptr TaggedPtr = Ptr;
Roland McGrath12ee7ad2021-04-13 15:03:54 -0700242 __asm__ __volatile__(
243 R"(
244 .arch_extension memtag
245 ldg %0, [%0]
246 )"
247 : "+r"(TaggedPtr)
248 :
249 : "memory");
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800250 return TaggedPtr;
251}
252
253#else
254
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800255inline bool systemSupportsMemoryTagging() {
256 UNREACHABLE("memory tagging not supported");
257}
258
259inline bool systemDetectsMemoryTagFaultsTestOnly() {
260 UNREACHABLE("memory tagging not supported");
261}
262
Vitaly Buka58be7da2021-05-27 10:10:50 -0700263inline void enableSystemMemoryTaggingTestOnly() {
264 UNREACHABLE("memory tagging not supported");
265}
266
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700267struct ScopedDisableMemoryTagChecks {
268 ScopedDisableMemoryTagChecks() {}
269};
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800270
Peter Collingbourne706ac402020-12-04 15:03:49 -0800271inline uptr selectRandomTag(uptr Ptr, uptr ExcludeMask) {
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800272 (void)Ptr;
Peter Collingbourne865f6742020-04-30 16:42:17 -0700273 (void)ExcludeMask;
Peter Collingbourne706ac402020-12-04 15:03:49 -0800274 UNREACHABLE("memory tagging not supported");
275}
276
Peter Collingbournecc3d4932020-12-21 18:39:03 -0800277inline uptr addFixedTag(uptr Ptr, uptr Tag) {
278 (void)Ptr;
279 (void)Tag;
280 UNREACHABLE("memory tagging not supported");
281}
282
Peter Collingbourne706ac402020-12-04 15:03:49 -0800283inline uptr storeTags(uptr Begin, uptr End) {
284 (void)Begin;
285 (void)End;
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800286 UNREACHABLE("memory tagging not supported");
287}
288
Peter Collingbourne34c88572021-04-20 14:54:32 -0700289inline void storeTag(uptr Ptr) {
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800290 (void)Ptr;
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800291 UNREACHABLE("memory tagging not supported");
292}
293
294inline uptr loadTag(uptr Ptr) {
295 (void)Ptr;
296 UNREACHABLE("memory tagging not supported");
297}
298
299#endif
300
Peter Collingbourne706ac402020-12-04 15:03:49 -0800301inline void setRandomTag(void *Ptr, uptr Size, uptr ExcludeMask,
302 uptr *TaggedBegin, uptr *TaggedEnd) {
303 *TaggedBegin = selectRandomTag(reinterpret_cast<uptr>(Ptr), ExcludeMask);
304 *TaggedEnd = storeTags(*TaggedBegin, *TaggedBegin + Size);
305}
306
Peter Collingbournecc3d4932020-12-21 18:39:03 -0800307inline void *untagPointer(void *Ptr) {
308 return reinterpret_cast<void *>(untagPointer(reinterpret_cast<uptr>(Ptr)));
309}
310
Peter Collingbourne75ee3bc2021-01-05 19:03:03 -0800311inline void *loadTag(void *Ptr) {
312 return reinterpret_cast<void *>(loadTag(reinterpret_cast<uptr>(Ptr)));
313}
314
315inline void *addFixedTag(void *Ptr, uptr Tag) {
316 return reinterpret_cast<void *>(
317 addFixedTag(reinterpret_cast<uptr>(Ptr), Tag));
318}
319
Peter Collingbourne6be49192020-12-15 14:26:10 -0800320template <typename Config>
321inline constexpr bool allocatorSupportsMemoryTagging() {
322 return archSupportsMemoryTagging() && Config::MaySupportMemoryTagging;
323}
324
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800325} // namespace scudo
326
327#endif