• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <android-base/file.h>
18 #include <androidfw/ResourceTypes.h>
19 #include <gtest/gtest.h>
20 
21 #include <cstdio>  // fclose
22 #include <fstream>
23 #include <memory>
24 #include <string>
25 
26 #include "R.h"
27 #include "TestConstants.h"
28 #include "TestHelpers.h"
29 #include "idmap2/LogInfo.h"
30 #include "idmap2/ResourceMapping.h"
31 
32 using android::Res_value;
33 
34 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
35 
36 namespace android::idmap2 {
37 
38 #define ASSERT_RESULT(r)                             \
39   do {                                               \
40     auto result = r;                                 \
41     ASSERT_TRUE(result) << result.GetErrorMessage(); \
42   } while (0)
43 
TestGetResourceMapping(const std::string & local_target_path,const std::string & local_overlay_path,const std::string & overlay_name,const PolicyBitmask & fulfilled_policies,bool enforce_overlayable)44 Result<ResourceMapping> TestGetResourceMapping(const std::string& local_target_path,
45                                                const std::string& local_overlay_path,
46                                                const std::string& overlay_name,
47                                                const PolicyBitmask& fulfilled_policies,
48                                                bool enforce_overlayable) {
49   const std::string target_path = (local_target_path[0] == '/')
50                                       ? local_target_path
51                                       : (GetTestDataPath() + "/" + local_target_path);
52   auto target = TargetResourceContainer::FromPath(target_path);
53   if (!target) {
54     return Error(target.GetError(), R"(Failed to load target "%s")", target_path.c_str());
55   }
56 
57   const std::string overlay_path = (local_overlay_path[0] == '/')
58                                        ? local_overlay_path
59                                        : (GetTestDataPath() + "/" + local_overlay_path);
60   auto overlay = OverlayResourceContainer::FromPath(overlay_path);
61   if (!overlay) {
62     return Error(overlay.GetError(), R"(Failed to load overlay "%s")", overlay_path.c_str());
63   }
64 
65   auto overlay_info = (*overlay)->FindOverlayInfo(overlay_name);
66   if (!overlay_info) {
67     return Error(overlay_info.GetError(), R"(Failed to find overlay name "%s")",
68                  overlay_name.c_str());
69   }
70 
71   LogInfo log_info;
72   return ResourceMapping::FromContainers(**target, **overlay, *overlay_info, fulfilled_policies,
73                                          enforce_overlayable, log_info);
74 }
75 
MappingExists(const ResourceMapping & mapping,ResourceId target_resource,ResourceId overlay_resource,bool rewrite)76 Result<Unit> MappingExists(const ResourceMapping& mapping, ResourceId target_resource,
77                            ResourceId overlay_resource, bool rewrite) {
78   auto target_map = mapping.GetTargetToOverlayMap();
79   auto entry_map = target_map.find(target_resource);
80   if (entry_map == target_map.end()) {
81     return Error("Failed to find mapping for target resource");
82   }
83 
84   auto actual_overlay_resource = std::get_if<ResourceId>(&entry_map->second);
85   if (actual_overlay_resource == nullptr) {
86     return Error("Target resource is not mapped to an overlay resource id");
87   }
88 
89   if (*actual_overlay_resource != overlay_resource) {
90     return Error(R"(Expected id: "0x%02x" Actual id: "0x%02x")", overlay_resource,
91                  *actual_overlay_resource);
92   }
93 
94   auto overlay_map = mapping.GetOverlayToTargetMap();
95   auto overlay_iter = overlay_map.find(overlay_resource);
96   if ((overlay_iter != overlay_map.end()) != rewrite) {
97     return Error(R"(Expected rewriting: "%s")", rewrite ? "true" : "false");
98   }
99 
100   if (rewrite && overlay_iter->second != target_resource) {
101     return Error(R"(Expected rewrite id: "0x%02x" Actual id: "0x%02x")", target_resource,
102                  overlay_iter->second);
103   }
104 
105   return Result<Unit>({});
106 }
107 
MappingExists(const ResourceMapping & mapping,const ResourceId & target_resource,const uint8_t type,const uint32_t value)108 Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& target_resource,
109                            const uint8_t type, const uint32_t value) {
110   auto target_map = mapping.GetTargetToOverlayMap();
111   auto entry_map = target_map.find(target_resource);
112   if (entry_map == target_map.end()) {
113     return Error("Failed to find mapping for target resource");
114   }
115 
116   auto actual_overlay_value = std::get_if<TargetValue>(&entry_map->second);
117   if (actual_overlay_value == nullptr) {
118     return Error("Target resource is not mapped to an inline value");
119   }
120 
121   if (actual_overlay_value->data_type != type) {
122     return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
123                  actual_overlay_value->data_type);
124   }
125 
126   if (actual_overlay_value->data_value != value) {
127     return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
128                  actual_overlay_value->data_value);
129   }
130 
131   return Result<Unit>({});
132 }
133 
TEST(ResourceMappingTests,ResourcesFromApkAssetsLegacy)134 TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
135   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
136                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
137 
138   ASSERT_TRUE(resources) << resources.GetErrorMessage();
139   auto& res = *resources;
140   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
141   ASSERT_RESULT(
142       MappingExists(res, R::target::integer::int1, R::overlay::integer::int1, false /* rewrite */));
143   ASSERT_RESULT(
144       MappingExists(res, R::target::string::str1, R::overlay::string::str1, false /* rewrite */));
145   ASSERT_RESULT(
146       MappingExists(res, R::target::string::str3, R::overlay::string::str3, false /* rewrite */));
147   ASSERT_RESULT(
148       MappingExists(res, R::target::string::str4, R::overlay::string::str4, false /* rewrite */));
149 }
150 
TEST(ResourceMappingTests,ResourcesFromApkAssetsNonMatchingNames)151 TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
152   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "SwapNames",
153                                           PolicyFlags::PUBLIC,
154                                           /* enforce_overlayable */ false);
155 
156   ASSERT_TRUE(resources) << resources.GetErrorMessage();
157   auto& res = *resources;
158   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
159   ASSERT_RESULT(
160       MappingExists(res, R::target::string::str1, R::overlay::string::str4, true /* rewrite */));
161   ASSERT_RESULT(
162       MappingExists(res, R::target::string::str3, R::overlay::string::str1, true /* rewrite */));
163   ASSERT_RESULT(
164       MappingExists(res, R::target::string::str4, R::overlay::string::str3, true /* rewrite */));
165 }
166 
TEST(ResourceMappingTests,DoNotRewriteNonOverlayResourceId)167 TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
168   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
169                                           "DifferentPackages", PolicyFlags::PUBLIC,
170                                           /* enforce_overlayable */ false);
171 
172   ASSERT_TRUE(resources) << resources.GetErrorMessage();
173   auto& res = *resources;
174   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
175   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
176   ASSERT_RESULT(MappingExists(res, R::target::string::str1, 0x0104000a,
177                               false /* rewrite */));  // -> android:string/ok
178   ASSERT_RESULT(
179       MappingExists(res, R::target::string::str3, R::overlay::string::str3, true /* rewrite */));
180 }
181 
TEST(ResourceMappingTests,InlineResources)182 TEST(ResourceMappingTests, InlineResources) {
183   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "Inline",
184                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
185 
186   constexpr size_t overlay_string_pool_size = 10U;
187   ASSERT_TRUE(resources) << resources.GetErrorMessage();
188   auto& res = *resources;
189   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
190   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
191   ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_STRING,
192                               overlay_string_pool_size + 0U));  // -> "Hello World"
193   ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U));
194 }
195 
TEST(ResourceMappingTests,FabricatedOverlay)196 TEST(ResourceMappingTests, FabricatedOverlay) {
197   auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
198                   .SetOverlayable("TestResources")
199                   .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
200                   .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
201                   .Build();
202 
203   ASSERT_TRUE(frro);
204   TemporaryFile tf;
205   std::ofstream out(tf.path);
206   ASSERT_TRUE((*frro).ToBinaryStream(out));
207   out.close();
208 
209   auto resources = TestGetResourceMapping("target/target.apk", tf.path, "SandTheme",
210                                           PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
211 
212   ASSERT_TRUE(resources) << resources.GetErrorMessage();
213   auto& res = *resources;
214   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
215   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
216   ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
217   ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
218 }
219 
TEST(ResourceMappingTests,CreateIdmapFromApkAssetsPolicySystemPublic)220 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
221   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
222                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
223                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
224                                           /* enforce_overlayable */ true);
225 
226   ASSERT_TRUE(resources) << resources.GetErrorMessage();
227   auto& res = *resources;
228   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
229   ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
230                               R::overlay::string::policy_public, true /* rewrite */));
231   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
232                               R::overlay::string::policy_system, true /* rewrite */));
233   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
234                               R::overlay::string::policy_system_vendor, true /* rewrite */));
235 }
236 
237 // Resources that are not declared as overlayable and resources that a protected by policies the
238 // overlay does not fulfill must not map to overlay resources.
TEST(ResourceMappingTests,CreateIdmapFromApkAssetsPolicySystemPublicInvalid)239 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
240   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
241                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
242                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
243                                           /* enforce_overlayable */ true);
244 
245   ASSERT_TRUE(resources) << resources.GetErrorMessage();
246   auto& res = *resources;
247   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
248   ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
249                               R::overlay::string::policy_public, true /* rewrite */));
250   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
251                               R::overlay::string::policy_system, true /* rewrite */));
252   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
253                               R::overlay::string::policy_system_vendor, true /* rewrite */));
254 }
255 
256 // Resources that are not declared as overlayable and resources that a protected by policies the
257 // overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
258 // off.
TEST(ResourceMappingTests,ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable)259 TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
260   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
261                                           TestConstants::OVERLAY_NAME_ALL_POLICIES,
262                                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
263                                           /* enforce_overlayable */ false);
264 
265   ASSERT_TRUE(resources) << resources.GetErrorMessage();
266   auto& res = *resources;
267   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U);
268   ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable,
269                               R::overlay::string::not_overlayable, true /* rewrite */));
270   ASSERT_RESULT(
271       MappingExists(res, R::target::string::other, R::overlay::string::other, true /* rewrite */));
272   ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor,
273                               R::overlay::string::policy_actor, true /* rewrite */));
274   ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, R::overlay::string::policy_odm,
275                               true /* rewrite */));
276   ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, R::overlay::string::policy_oem,
277                               true /* rewrite */));
278   ASSERT_RESULT(MappingExists(res, R::target::string::policy_product,
279                               R::overlay::string::policy_product, true /* rewrite */));
280   ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
281                               R::overlay::string::policy_public, true /* rewrite */));
282   ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
283                               R::overlay::string::policy_config_signature, true /* rewrite */));
284   ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature,
285                               R::overlay::string::policy_signature, true /* rewrite */));
286   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
287                               R::overlay::string::policy_system, true /* rewrite */));
288   ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
289                               R::overlay::string::policy_system_vendor, true /* rewrite */));
290 }
291 
292 // Overlays that do not target an <overlayable> tag can overlay any resource if overlayable
293 // enforcement is disabled.
TEST(ResourceMappingTests,ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName)294 TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
295   auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
296                                           PolicyFlags::PUBLIC,
297                                           /* enforce_overlayable */ false);
298 
299   ASSERT_TRUE(resources) << resources.GetErrorMessage();
300   auto& res = *resources;
301   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
302   ASSERT_RESULT(
303       MappingExists(res, R::target::integer::int1, R::overlay::integer::int1, false /* rewrite */));
304   ASSERT_RESULT(
305       MappingExists(res, R::target::string::str1, R::overlay::string::str1, false /* rewrite */));
306   ASSERT_RESULT(
307       MappingExists(res, R::target::string::str3, R::overlay::string::str3, false /* rewrite */));
308   ASSERT_RESULT(
309       MappingExists(res, R::target::string::str4, R::overlay::string::str4, false /* rewrite */));
310 }
311 
312 // Overlays that are neither pre-installed nor signed with the same signature as the target cannot
313 // overlay packages that have not defined overlayable resources.
TEST(ResourceMappingTests,ResourcesFromApkAssetsDefaultPoliciesPublicFail)314 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
315   auto resources = TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
316                                           "NoTargetName", PolicyFlags::PUBLIC,
317                                           /* enforce_overlayable */ true);
318 
319   ASSERT_TRUE(resources) << resources.GetErrorMessage();
320   ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
321 }
322 
323 // Overlays that are pre-installed or are signed with the same signature as the target  or are
324 // signed with the same signature as the reference package can overlay packages that have not
325 // defined overlayable resources.
TEST(ResourceMappingTests,ResourcesFromApkAssetsDefaultPolicies)326 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
327   auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) {
328     auto resources =
329         TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
330                                TestConstants::OVERLAY_NAME_ALL_POLICIES, fulfilled_policies,
331                                /* enforce_overlayable */ true);
332 
333     ASSERT_TRUE(resources) << resources.GetErrorMessage();
334     auto& res = *resources;
335     ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U);
336     ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable,
337                                 R::overlay::string::not_overlayable, true /* rewrite */));
338     ASSERT_RESULT(MappingExists(res, R::target::string::other, R::overlay::string::other,
339                                 true /* rewrite */));
340     ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor,
341                                 R::overlay::string::policy_actor, true /* rewrite */));
342     ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, R::overlay::string::policy_odm,
343                                 true /* rewrite */));
344     ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, R::overlay::string::policy_oem,
345                                 true /* rewrite */));
346     ASSERT_RESULT(MappingExists(res, R::target::string::policy_product,
347                                 R::overlay::string::policy_product, true /* rewrite */));
348     ASSERT_RESULT(MappingExists(res, R::target::string::policy_public,
349                                 R::overlay::string::policy_public, true /* rewrite */));
350     ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
351                                 R::overlay::string::policy_config_signature, true /* rewrite */));
352     ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature,
353                                 R::overlay::string::policy_signature, true /* rewrite */));
354     ASSERT_RESULT(MappingExists(res, R::target::string::policy_system,
355                                 R::overlay::string::policy_system, true /* rewrite */));
356     ASSERT_RESULT(MappingExists(res, R::target::string::policy_system_vendor,
357                                 R::overlay::string::policy_system_vendor, true /* rewrite */));
358   };
359 
360   CheckEntries(PolicyFlags::SIGNATURE);
361   CheckEntries(PolicyFlags::CONFIG_SIGNATURE);
362   CheckEntries(PolicyFlags::PRODUCT_PARTITION);
363   CheckEntries(PolicyFlags::SYSTEM_PARTITION);
364   CheckEntries(PolicyFlags::VENDOR_PARTITION);
365   CheckEntries(PolicyFlags::ODM_PARTITION);
366   CheckEntries(PolicyFlags::OEM_PARTITION);
367 }
368 
369 }  // namespace android::idmap2
370