1 // Copyright 2013 Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // Unittests for OMAP related functions.
30
31 #include "common/windows/omap.h"
32
33 #include "gmock/gmock.h"
34 #include "gtest/gtest.h"
35
36 namespace google_breakpad {
37
38 // Equality operators for ContainerEq. These must be outside of the anonymous
39 // namespace in order for them to be found.
operator ==(const MappedRange & mr1,const MappedRange & mr2)40 bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
41 return mr1.rva_original == mr2.rva_original &&
42 mr1.rva_transformed == mr2.rva_transformed &&
43 mr1.length == mr2.length &&
44 mr1.injected == mr2.injected &&
45 mr1.removed == mr2.removed;
46 }
operator ==(const EndpointIndex & ei1,const EndpointIndex & ei2)47 bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
48 return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
49 }
50
51 // Pretty printers for more meaningful error messages. Also need to be outside
52 // the anonymous namespace.
operator <<(std::ostream & os,const MappedRange & mr)53 std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
54 os << "MappedRange(rva_original=" << mr.rva_original
55 << ", rva_transformed=" << mr.rva_transformed
56 << ", length=" << mr.length
57 << ", injected=" << mr.injected
58 << ", removed=" << mr.removed << ")";
59 return os;
60 }
operator <<(std::ostream & os,const EndpointIndex & ei)61 std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
62 os << "EndpointIndex(endpoint=" << ei.endpoint
63 << ", index=" << ei.index << ")";
64 return os;
65 }
operator <<(std::ostream & os,const AddressRange & ar)66 std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
67 os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
68 return os;
69 }
70
71 namespace {
72
CreateOmap(DWORD rva,DWORD rvaTo)73 OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
74 OMAP o = { rva, rvaTo };
75 return o;
76 }
77
CreateMappedRange(DWORD rva_original,DWORD rva_transformed,DWORD length,DWORD injected,DWORD removed)78 MappedRange CreateMappedRange(DWORD rva_original,
79 DWORD rva_transformed,
80 DWORD length,
81 DWORD injected,
82 DWORD removed) {
83 MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
84 return mr;
85 }
86
CreateEndpointIndex(DWORD endpoint,size_t index)87 EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
88 EndpointIndex ei = { endpoint, index };
89 return ei;
90 }
91
92 // (C is removed)
93 // Original : A B C D E F G H
94 // Transformed: A B D F E * H1 G1 G2 H2
95 // (* is injected, G is copied, H is split)
96 // A is implied.
97
98 // Layout of the original image.
99 const AddressRange B(100, 15);
100 const AddressRange C(B.end(), 10);
101 const AddressRange D(C.end(), 25);
102 const AddressRange E(D.end(), 10);
103 const AddressRange F(E.end(), 40);
104 const AddressRange G(F.end(), 3);
105 const AddressRange H(G.end(), 7);
106
107 // Layout of the transformed image.
108 const AddressRange Bt(100, 15);
109 const AddressRange Dt(Bt.end(), 20); // D is shortened.
110 const AddressRange Ft(Dt.end(), F.length);
111 const AddressRange Et(Ft.end(), E.length);
112 const AddressRange injected(Et.end(), 5);
113 const AddressRange H1t(injected.end(), 4); // H is split.
114 const AddressRange G1t(H1t.end(), G.length); // G is copied.
115 const AddressRange G2t(G1t.end(), G.length); // G is copied.
116 const AddressRange H2t(G2t.end(), 3); // H is split.
117
118 class BuildImageMapTest : public testing::Test {
119 public:
120 static const DWORD kInvalidAddress = 0xFFFFFFFF;
121
InitOmapData()122 void InitOmapData() {
123 omap_data.length_original = H.end();
124
125 // Build the OMAPTO vector (from transformed to original).
126 omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
127 omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
128 omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
129 omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
130 omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
131 omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
132 omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
133 omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
134 omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
135 omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
136
137 // Build the OMAPFROM vector (from original to transformed).
138 omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
139 omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
140 omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
141 omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
142 omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
143 omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
144 omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
145 omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
146 omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
147 }
148
149 OmapData omap_data;
150 };
151
152 } // namespace
153
TEST_F(BuildImageMapTest,EmptyImageMapOnEmptyOmapData)154 TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
155 ASSERT_EQ(0u, omap_data.omap_from.size());
156 ASSERT_EQ(0u, omap_data.omap_to.size());
157 ASSERT_EQ(0u, omap_data.length_original);
158
159 ImageMap image_map;
160 BuildImageMap(omap_data, &image_map);
161 EXPECT_EQ(0u, image_map.mapping.size());
162 EXPECT_EQ(0u, image_map.endpoint_index_map.size());
163 }
164
TEST_F(BuildImageMapTest,ImageMapIsCorrect)165 TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
166 InitOmapData();
167 ASSERT_LE(0u, omap_data.omap_from.size());
168 ASSERT_LE(0u, omap_data.omap_to.size());
169 ASSERT_LE(0u, omap_data.length_original);
170
171 ImageMap image_map;
172 BuildImageMap(omap_data, &image_map);
173 EXPECT_LE(9u, image_map.mapping.size());
174 EXPECT_LE(9u, image_map.endpoint_index_map.size());
175
176 Mapping mapping;
177 mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
178 // C is removed, and it originally comes immediately after B.
179 mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
180 // D is shortened by a length of 5.
181 mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
182 // The injected content comes immediately after E in the transformed image.
183 mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
184 0));
185 mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
186 // G is copied so creates two entries.
187 mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
188 mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
189 // H is split, so create two entries.
190 mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
191 mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
192 0, 0));
193 EXPECT_THAT(mapping,
194 testing::ContainerEq(image_map.mapping));
195
196 EndpointIndexMap endpoint_index_map;
197 endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
198 endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
199 endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
200 endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
201 endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
202 // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
203 endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
204 // H is split so we expect 2 endpoints to show up attributed to it.
205 endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
206 endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
207 endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
208 EXPECT_THAT(endpoint_index_map,
209 testing::ContainerEq(image_map.endpoint_index_map));
210 }
211
212 namespace {
213
214 class MapAddressRangeTest : public BuildImageMapTest {
215 public:
216 typedef BuildImageMapTest Super;
SetUp()217 virtual void SetUp() {
218 Super::SetUp();
219 InitOmapData();
220 BuildImageMap(omap_data, &image_map);
221 }
222
223 ImageMap image_map;
224
225 private:
226 using BuildImageMapTest::InitOmapData;
227 using BuildImageMapTest::omap_data;
228 };
229
230 } // namespace
231
TEST_F(MapAddressRangeTest,EmptyImageMapReturnsIdentity)232 TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
233 ImageMap im;
234 AddressRangeVector mapped_ranges;
235 AddressRange ar(0, 1024);
236 MapAddressRange(im, ar, &mapped_ranges);
237 EXPECT_EQ(1u, mapped_ranges.size());
238 EXPECT_EQ(ar, mapped_ranges[0]);
239 }
240
TEST_F(MapAddressRangeTest,MapOutOfImage)241 TEST_F(MapAddressRangeTest, MapOutOfImage) {
242 AddressRangeVector mapped_ranges;
243 MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
244 EXPECT_EQ(0u, mapped_ranges.size());
245 }
246
TEST_F(MapAddressRangeTest,MapIdentity)247 TEST_F(MapAddressRangeTest, MapIdentity) {
248 AddressRangeVector mapped_ranges;
249 MapAddressRange(image_map, B, &mapped_ranges);
250 EXPECT_EQ(1u, mapped_ranges.size());
251 EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
252 }
253
TEST_F(MapAddressRangeTest,MapReorderedContiguous)254 TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
255 AddressRangeVector mapped_ranges;
256
257 AddressRange DEF(D.rva, F.end() - D.rva);
258 MapAddressRange(image_map, DEF, &mapped_ranges);
259 EXPECT_EQ(1u, mapped_ranges.size());
260
261 AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
262 EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
263 }
264
TEST_F(MapAddressRangeTest,MapEmptySingle)265 TEST_F(MapAddressRangeTest, MapEmptySingle) {
266 AddressRangeVector mapped_ranges;
267 MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
268 EXPECT_EQ(1u, mapped_ranges.size());
269 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
270 }
271
TEST_F(MapAddressRangeTest,MapEmptyCopied)272 TEST_F(MapAddressRangeTest, MapEmptyCopied) {
273 AddressRangeVector mapped_ranges;
274 MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
275 EXPECT_EQ(2u, mapped_ranges.size());
276 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
277 AddressRange(G2t.rva, 0)));
278 }
279
TEST_F(MapAddressRangeTest,MapCopiedContiguous)280 TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
281 AddressRangeVector mapped_ranges;
282 MapAddressRange(image_map, G, &mapped_ranges);
283 EXPECT_EQ(1u, mapped_ranges.size());
284 EXPECT_THAT(mapped_ranges, testing::ElementsAre(
285 AddressRange(G1t.rva, G2t.end() - G1t.rva)));
286 }
287
TEST_F(MapAddressRangeTest,MapSplitDiscontiguous)288 TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
289 AddressRangeVector mapped_ranges;
290 MapAddressRange(image_map, H, &mapped_ranges);
291 EXPECT_EQ(2u, mapped_ranges.size());
292 EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
293 }
294
TEST_F(MapAddressRangeTest,MapInjected)295 TEST_F(MapAddressRangeTest, MapInjected) {
296 AddressRangeVector mapped_ranges;
297
298 AddressRange EFGH(E.rva, H.end() - E.rva);
299 MapAddressRange(image_map, EFGH, &mapped_ranges);
300 EXPECT_EQ(1u, mapped_ranges.size());
301
302 AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
303 EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
304 }
305
TEST_F(MapAddressRangeTest,MapRemovedEntirely)306 TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
307 AddressRangeVector mapped_ranges;
308 MapAddressRange(image_map, C, &mapped_ranges);
309 EXPECT_EQ(0u, mapped_ranges.size());
310 }
311
TEST_F(MapAddressRangeTest,MapRemovedPartly)312 TEST_F(MapAddressRangeTest, MapRemovedPartly) {
313 AddressRangeVector mapped_ranges;
314 MapAddressRange(image_map, D, &mapped_ranges);
315 EXPECT_EQ(1u, mapped_ranges.size());
316 EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
317 }
318
TEST_F(MapAddressRangeTest,MapFull)319 TEST_F(MapAddressRangeTest, MapFull) {
320 AddressRangeVector mapped_ranges;
321
322 AddressRange AH(0, H.end());
323 MapAddressRange(image_map, AH, &mapped_ranges);
324 EXPECT_EQ(1u, mapped_ranges.size());
325
326 AddressRange AHt(0, H2t.end());
327 EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
328 }
329
330 } // namespace google_breakpad
331