1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gtest/gtest.h"
18
19 #include <memory>
20
21 #include "berberis/base/large_mmap.h"
22 #include "berberis/guest_os_primitives/guest_map_shadow.h"
23 #include "berberis/guest_state/guest_addr.h"
24
25 namespace berberis {
26
27 namespace {
28
29 class GuestMapShadowTest : public ::testing::Test {
30 protected:
SetUp()31 void SetUp() override {
32 ::testing::Test::SetUp();
33 InitLargeMmap();
34 }
35 };
36
37 constexpr GuestAddr kGuestAddr = GuestAddr{0x7f018000};
38 constexpr size_t kGuestRegionSize = GuestAddr{0x00020000};
39
TEST_F(GuestMapShadowTest,smoke)40 TEST_F(GuestMapShadowTest, smoke) {
41 auto shadow = std::make_unique<GuestMapShadow>();
42
43 ASSERT_EQ(kBitUnset, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
44 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, 1));
45 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
46
47 shadow->SetExecutable(kGuestAddr, kGuestRegionSize / 2);
48
49 ASSERT_EQ(kBitMixed, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
50 ASSERT_EQ(kBitSet, shadow->GetExecutable(kGuestAddr, kGuestRegionSize / 2));
51 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, 1));
52 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kGuestRegionSize / 2));
53 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
54
55 shadow->SetExecutable(kGuestAddr, kGuestRegionSize);
56 ASSERT_EQ(kBitSet, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
57 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, 1));
58 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kGuestRegionSize / 2));
59 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
60
61 shadow->ClearExecutable(kGuestAddr, kGuestRegionSize * 2);
62 ASSERT_EQ(kBitUnset, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
63 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, 1));
64 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize / 2));
65 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
66 }
67
TEST_F(GuestMapShadowTest,remap)68 TEST_F(GuestMapShadowTest, remap) {
69 constexpr GuestAddr kRemapAddr = 0x00107000;
70 constexpr size_t kRemapRegionSize1 = kGuestRegionSize / 2;
71 constexpr size_t kRemapRegionSize2 = kGuestRegionSize * 2;
72
73 auto shadow = std::make_unique<GuestMapShadow>();
74
75 shadow->SetExecutable(kGuestAddr, kGuestRegionSize);
76 ASSERT_EQ(kBitSet, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
77 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, 1));
78 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kGuestRegionSize / 2));
79 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
80
81 shadow->RemapExecutable(kGuestAddr, kGuestRegionSize, kRemapAddr, kRemapRegionSize1);
82 ASSERT_EQ(kBitUnset, shadow->GetExecutable(kGuestAddr, kGuestRegionSize));
83 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, 1));
84 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize / 2));
85 ASSERT_TRUE(!shadow->IsExecutable(kGuestAddr, kGuestRegionSize));
86
87 ASSERT_EQ(kBitSet, shadow->GetExecutable(kRemapAddr, kRemapRegionSize1));
88 ASSERT_TRUE(shadow->IsExecutable(kRemapAddr, 1));
89 ASSERT_TRUE(shadow->IsExecutable(kRemapAddr, kRemapRegionSize1));
90
91 shadow->RemapExecutable(kRemapAddr, kRemapRegionSize1, kGuestAddr, kRemapRegionSize2);
92 ASSERT_EQ(kBitUnset, shadow->GetExecutable(kRemapAddr, kRemapRegionSize1));
93 ASSERT_TRUE(!shadow->IsExecutable(kRemapAddr, 1));
94 ASSERT_TRUE(!shadow->IsExecutable(kRemapAddr, kRemapRegionSize1));
95
96 ASSERT_EQ(kBitSet, shadow->GetExecutable(kGuestAddr, kRemapRegionSize2));
97 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, 1));
98 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kRemapRegionSize2 / 2));
99 ASSERT_TRUE(shadow->IsExecutable(kGuestAddr, kRemapRegionSize2));
100 }
101
TEST_F(GuestMapShadowTest,ProtectedMappings)102 TEST_F(GuestMapShadowTest, ProtectedMappings) {
103 const char* kStart = ToHostAddr<char>(0x00107000);
104 const char* kEnd = kStart + kGuestRegionSize;
105 const size_t kHalf = kGuestRegionSize / 2;
106
107 auto shadow = std::make_unique<GuestMapShadow>();
108
109 shadow->AddProtectedMapping(kStart, kEnd);
110
111 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kStart, kEnd));
112
113 // Intersecting mappings are also protected.
114 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kStart - kHalf, kEnd - kHalf));
115 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kStart + kHalf, kEnd + kHalf));
116
117 // Adjacent mappings are not protected.
118 EXPECT_FALSE(shadow->IntersectsWithProtectedMapping(kStart - kGuestRegionSize, kStart));
119 EXPECT_FALSE(shadow->IntersectsWithProtectedMapping(kEnd, kEnd + kGuestRegionSize));
120
121 // Add and test another mapping.
122
123 const char* kAnotherStart = kStart + kGuestRegionSize;
124 const char* kAnotherEnd = kAnotherStart + kGuestRegionSize;
125 shadow->AddProtectedMapping(kAnotherStart, kAnotherEnd);
126
127 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kAnotherStart, kAnotherEnd));
128
129 // Intersecting mappings, including those that span across
130 // multiple protected mappings, are also protected.
131 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kAnotherStart - kHalf, kAnotherEnd - kHalf));
132 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kAnotherStart + kHalf, kAnotherEnd + kHalf));
133 EXPECT_TRUE(shadow->IntersectsWithProtectedMapping(kStart - kHalf, kAnotherEnd + kHalf));
134
135 // Adjacent mappings, including between the protected mappings, are not protected.
136 EXPECT_FALSE(shadow->IntersectsWithProtectedMapping(kEnd, kAnotherStart));
137 EXPECT_FALSE(shadow->IntersectsWithProtectedMapping(kAnotherEnd, kAnotherEnd + kGuestRegionSize));
138 }
139
140 } // namespace
141
142 } // namespace berberis
143