• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- memtag_test.cpp -----------------------------------------*- 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 #include "common.h"
10 #include "mem_map.h"
11 #include "memtag.h"
12 #include "platform.h"
13 #include "tests/scudo_unit_test.h"
14 
15 #if SCUDO_LINUX
16 namespace scudo {
17 
TEST(MemtagBasicDeathTest,Unsupported)18 TEST(MemtagBasicDeathTest, Unsupported) {
19   if (archSupportsMemoryTagging())
20     GTEST_SKIP();
21 
22   EXPECT_DEATH(archMemoryTagGranuleSize(), "not supported");
23   EXPECT_DEATH(untagPointer((uptr)0), "not supported");
24   EXPECT_DEATH(extractTag((uptr)0), "not supported");
25 
26   EXPECT_DEATH(systemSupportsMemoryTagging(), "not supported");
27   EXPECT_DEATH(systemDetectsMemoryTagFaultsTestOnly(), "not supported");
28   EXPECT_DEATH(enableSystemMemoryTaggingTestOnly(), "not supported");
29 
30   EXPECT_DEATH(selectRandomTag((uptr)0, 0), "not supported");
31   EXPECT_DEATH(addFixedTag((uptr)0, 1), "not supported");
32   EXPECT_DEATH(storeTags((uptr)0, (uptr)0 + sizeof(0)), "not supported");
33   EXPECT_DEATH(storeTag((uptr)0), "not supported");
34   EXPECT_DEATH(loadTag((uptr)0), "not supported");
35 
36   EXPECT_DEATH(setRandomTag(nullptr, 64, 0, nullptr, nullptr), "not supported");
37   EXPECT_DEATH(untagPointer(nullptr), "not supported");
38   EXPECT_DEATH(loadTag(nullptr), "not supported");
39   EXPECT_DEATH(addFixedTag(nullptr, 0), "not supported");
40 }
41 
42 class MemtagTest : public Test {
43 protected:
SetUp()44   void SetUp() override {
45     if (!archSupportsMemoryTagging() || !systemDetectsMemoryTagFaultsTestOnly())
46       GTEST_SKIP() << "Memory tagging is not supported";
47 
48     BufferSize = getPageSizeCached();
49     ASSERT_FALSE(MemMap.isAllocated());
50     ASSERT_TRUE(MemMap.map(/*Addr=*/0U, BufferSize, "MemtagTest", MAP_MEMTAG));
51     ASSERT_NE(MemMap.getBase(), 0U);
52     Addr = MemMap.getBase();
53     Buffer = reinterpret_cast<u8 *>(Addr);
54     EXPECT_TRUE(isAligned(Addr, archMemoryTagGranuleSize()));
55     EXPECT_EQ(Addr, untagPointer(Addr));
56   }
57 
TearDown()58   void TearDown() override {
59     if (Buffer) {
60       ASSERT_TRUE(MemMap.isAllocated());
61       MemMap.unmap(MemMap.getBase(), MemMap.getCapacity());
62     }
63   }
64 
65   uptr BufferSize = 0;
66   scudo::MemMapT MemMap = {};
67   u8 *Buffer = nullptr;
68   uptr Addr = 0;
69 };
70 
71 using MemtagDeathTest = MemtagTest;
72 
TEST_F(MemtagTest,ArchMemoryTagGranuleSize)73 TEST_F(MemtagTest, ArchMemoryTagGranuleSize) {
74   EXPECT_GT(archMemoryTagGranuleSize(), 1u);
75   EXPECT_TRUE(isPowerOfTwo(archMemoryTagGranuleSize()));
76 }
77 
TEST_F(MemtagTest,ExtractTag)78 TEST_F(MemtagTest, ExtractTag) {
79   uptr Tags = 0;
80   // Try all value for the top byte and check the tags values are in the
81   // expected range.
82   for (u64 Top = 0; Top < 0x100; ++Top)
83     Tags = Tags | (1u << extractTag(Addr | (Top << 56)));
84   EXPECT_EQ(0xffffull, Tags);
85 }
86 
TEST_F(MemtagDeathTest,AddFixedTag)87 TEST_F(MemtagDeathTest, AddFixedTag) {
88   for (uptr Tag = 0; Tag < 0x10; ++Tag)
89     EXPECT_EQ(Tag, extractTag(addFixedTag(Addr, Tag)));
90   if (SCUDO_DEBUG) {
91     EXPECT_DEBUG_DEATH(addFixedTag(Addr, 16), "");
92     EXPECT_DEBUG_DEATH(addFixedTag(~Addr, 0), "");
93   }
94 }
95 
TEST_F(MemtagTest,UntagPointer)96 TEST_F(MemtagTest, UntagPointer) {
97   uptr UnTagMask = untagPointer(~uptr(0));
98   for (u64 Top = 0; Top < 0x100; ++Top) {
99     uptr Ptr = (Addr | (Top << 56)) & UnTagMask;
100     EXPECT_EQ(addFixedTag(Ptr, 0), untagPointer(Ptr));
101   }
102 }
103 
TEST_F(MemtagDeathTest,ScopedDisableMemoryTagChecks)104 TEST_F(MemtagDeathTest, ScopedDisableMemoryTagChecks) {
105   u8 *P = reinterpret_cast<u8 *>(addFixedTag(Addr, 1));
106   EXPECT_NE(P, Buffer);
107 
108   EXPECT_DEATH(*P = 20, "");
109   ScopedDisableMemoryTagChecks Disable;
110   *P = 10;
111 }
112 
TEST_F(MemtagTest,SelectRandomTag)113 TEST_F(MemtagTest, SelectRandomTag) {
114   for (uptr SrcTag = 0; SrcTag < 0x10; ++SrcTag) {
115     uptr Ptr = addFixedTag(Addr, SrcTag);
116     uptr Tags = 0;
117     for (uptr I = 0; I < 100000; ++I)
118       Tags = Tags | (1u << extractTag(selectRandomTag(Ptr, 0)));
119     EXPECT_EQ(0xfffeull, Tags);
120   }
121 }
122 
TEST_F(MemtagTest,SelectRandomTagWithMask)123 TEST_F(MemtagTest, SelectRandomTagWithMask) {
124   for (uptr j = 0; j < 32; ++j) {
125     for (uptr i = 0; i < 1000; ++i)
126       EXPECT_NE(j, extractTag(selectRandomTag(Addr, 1ull << j)));
127   }
128 }
129 
TEST_F(MemtagDeathTest,SKIP_NO_DEBUG (LoadStoreTagUnaligned))130 TEST_F(MemtagDeathTest, SKIP_NO_DEBUG(LoadStoreTagUnaligned)) {
131   for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
132     if (P % archMemoryTagGranuleSize() == 0)
133       continue;
134     EXPECT_DEBUG_DEATH(loadTag(P), "");
135     EXPECT_DEBUG_DEATH(storeTag(P), "");
136   }
137 }
138 
TEST_F(MemtagTest,LoadStoreTag)139 TEST_F(MemtagTest, LoadStoreTag) {
140   uptr Base = Addr + 0x100;
141   uptr Tagged = addFixedTag(Base, 7);
142   storeTag(Tagged);
143 
144   EXPECT_EQ(Base - archMemoryTagGranuleSize(),
145             loadTag(Base - archMemoryTagGranuleSize()));
146   EXPECT_EQ(Tagged, loadTag(Base));
147   EXPECT_EQ(Base + archMemoryTagGranuleSize(),
148             loadTag(Base + archMemoryTagGranuleSize()));
149 }
150 
TEST_F(MemtagDeathTest,SKIP_NO_DEBUG (StoreTagsUnaligned))151 TEST_F(MemtagDeathTest, SKIP_NO_DEBUG(StoreTagsUnaligned)) {
152   for (uptr P = Addr; P < Addr + 4 * archMemoryTagGranuleSize(); ++P) {
153     uptr Tagged = addFixedTag(P, 5);
154     if (Tagged % archMemoryTagGranuleSize() == 0)
155       continue;
156     EXPECT_DEBUG_DEATH(storeTags(Tagged, Tagged), "");
157   }
158 }
159 
TEST_F(MemtagTest,StoreTags)160 TEST_F(MemtagTest, StoreTags) {
161   const uptr MaxTaggedSize = 4 * archMemoryTagGranuleSize();
162   for (uptr Size = 0; Size <= MaxTaggedSize; ++Size) {
163     uptr NoTagBegin = Addr + archMemoryTagGranuleSize();
164     uptr NoTagEnd = NoTagBegin + Size;
165 
166     u8 Tag = 5;
167 
168     uptr TaggedBegin = addFixedTag(NoTagBegin, Tag);
169     uptr TaggedEnd = addFixedTag(NoTagEnd, Tag);
170 
171     EXPECT_EQ(roundUp(TaggedEnd, archMemoryTagGranuleSize()),
172               storeTags(TaggedBegin, TaggedEnd));
173 
174     uptr LoadPtr = Addr;
175     // Untagged left granule.
176     EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
177 
178     for (LoadPtr += archMemoryTagGranuleSize(); LoadPtr < NoTagEnd;
179          LoadPtr += archMemoryTagGranuleSize()) {
180       EXPECT_EQ(addFixedTag(LoadPtr, 5), loadTag(LoadPtr));
181     }
182 
183     // Untagged right granule.
184     EXPECT_EQ(LoadPtr, loadTag(LoadPtr));
185 
186     // Reset tags without using StoreTags.
187     MemMap.releasePagesToOS(Addr, BufferSize);
188   }
189 }
190 
191 } // namespace scudo
192 
193 #endif
194