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