Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19823450 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

Enforce overlayable API when defined

If a package defines overlayable resources, then do not allow resources
that are not defined as overlayable to be overlaid.

Bug:123600120
Test: idmap2_tests and cts-tradefed run cts -m CtsRROTestCases
Change-Id: I35120a97ccf4650e67c7ba65a60f4f3c51b0e627
parent f727b8cf
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -16,11 +16,11 @@ cc_defaults {
    name: "idmap2_defaults",
    tidy: true,
    tidy_checks: [
        "modernize-*",
        "-modernize-avoid-c-arrays",
        "android-*",
        "misc-*",
        "modernize-*",
        "readability-*",
        "-modernize-avoid-c-arrays",
    ],
    tidy_flags: [
        "-system-headers",
+2 −2
Original line number Diff line number Diff line
@@ -281,10 +281,10 @@ bool CheckOverlayable(const LoadedPackage& target_package,
  if (overlayable_info == nullptr) {
    // If the resource does not have an overlayable definition, allow the resource to be overlaid.
    // Once overlayable enforcement is turned on, this check will return false.
    return true;
    return !target_package.DefinesOverlayable();
  }

  if (!overlay_info.target_name.empty() && overlay_info.target_name != overlayable_info->name) {
  if (overlay_info.target_name != overlayable_info->name) {
    // If the overlay supplies a target overlayable name, the resource must belong to the
    // overlayable defined with the specified name to be overlaid.
    return false;
+17 −10
Original line number Diff line number Diff line
@@ -40,9 +40,14 @@ TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) {
                               const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
  ASSERT_THAT(v, NotNull());
  ASSERT_EQ(v->size(), 6U);
  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
            std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
                                   root + "/system-overlay", root + "/system-overlay-invalid"}));
  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({
                                                             root + "/.",
                                                             root + "/..",
                                                             root + "/overlay",
                                                             root + "/target",
                                                             root + "/system-overlay",
                                                             root + "/system-overlay-invalid",
                                                         }));
}

TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
@@ -51,12 +56,14 @@ TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
    return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
  });
  ASSERT_THAT(v, NotNull());
  ASSERT_EQ(v->size(), 6U);
  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
            std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
                                   root + "/overlay/overlay-static-1.apk",
                                   root + "/overlay/overlay-static-2.apk",
                                   root + "/system-overlay/system-overlay.apk",
  ASSERT_EQ(v->size(), 9U);
  ASSERT_EQ(
      std::set<std::string>(v->begin(), v->end()),
      std::set<std::string>(
          {root + "/target/target.apk", root + "/target/target-no-overlayable.apk",
           root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk",
           root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-static-1.apk",
           root + "/overlay/overlay-static-2.apk", root + "/system-overlay/system-overlay.apk",
           root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
}

+14 −0
Original line number Diff line number Diff line
@@ -163,8 +163,12 @@ TEST_F(Idmap2BinaryTests, Dump) {
TEST_F(Idmap2BinaryTests, Scan) {
  SKIP_TEST_IF_CANT_EXEC_IDMAP2;

  const std::string overlay_static_no_name_apk_path =
      GetTestDataPath() + "/overlay/overlay-no-name-static.apk";
  const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk";
  const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk";
  const std::string idmap_static_no_name_path =
      Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_no_name_apk_path);
  const std::string idmap_static_1_path =
      Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_1_apk_path);
  const std::string idmap_static_2_path =
@@ -184,11 +188,18 @@ TEST_F(Idmap2BinaryTests, Scan) {
  ASSERT_THAT(result, NotNull());
  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
  std::stringstream expected;
  expected << idmap_static_no_name_path << std::endl;
  expected << idmap_static_1_path << std::endl;
  expected << idmap_static_2_path << std::endl;
  ASSERT_EQ(result->stdout, expected.str());

  std::stringstream error;
  auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path);
  auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string);
  auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream, error);
  ASSERT_THAT(idmap_static_no_name, NotNull());
  ASSERT_IDMAP(*idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path);

  auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path);
  auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string);
  auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream, error);
@@ -201,6 +212,7 @@ TEST_F(Idmap2BinaryTests, Scan) {
  ASSERT_THAT(idmap_static_2, NotNull());
  ASSERT_IDMAP(*idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path);

  unlink(idmap_static_no_name_path.c_str());
  unlink(idmap_static_2_path.c_str());
  unlink(idmap_static_1_path.c_str());

@@ -218,6 +230,7 @@ TEST_F(Idmap2BinaryTests, Scan) {
  ASSERT_THAT(result, NotNull());
  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
  ASSERT_EQ(result->stdout, expected.str());
  unlink(idmap_static_no_name_path.c_str());
  unlink(idmap_static_2_path.c_str());
  unlink(idmap_static_1_path.c_str());

@@ -236,6 +249,7 @@ TEST_F(Idmap2BinaryTests, Scan) {
  ASSERT_THAT(result, NotNull());
  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
  ASSERT_EQ(result->stdout, expected.str());
  unlink(idmap_static_no_name_path.c_str());
  unlink(idmap_static_2_path.c_str());
  unlink(idmap_static_1_path.c_str());

+96 −11
Original line number Diff line number Diff line
@@ -224,7 +224,8 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
  ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
}

TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  ASSERT_THAT(target_apk, NotNull());
@@ -260,7 +261,8 @@ TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_system_vendor
}

TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  ASSERT_THAT(target_apk, NotNull());
@@ -288,20 +290,60 @@ TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
  ASSERT_EQ(types.size(), 1U);

  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
  ASSERT_EQ(types[0]->GetEntryCount(), 3U);
  ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
  ASSERT_EQ(types[0]->GetEntry(0), 0x0003U);  // string/policy_public
  ASSERT_EQ(types[0]->GetEntry(1), 0x0004U);  // string/policy_system
  ASSERT_EQ(types[0]->GetEntry(2), 0x0005U);  // string/policy_system_vendor
}

// Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  ASSERT_THAT(target_apk, NotNull());

  const std::string overlay_apk_path(GetTestDataPath() +
                                     "/system-overlay-invalid/system-overlay-invalid.apk");
  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
  ASSERT_THAT(overlay_apk, NotNull());

  std::stringstream error;
  std::unique_ptr<const Idmap> idmap =
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
                           /* enforce_overlayable */ false, error);
  ASSERT_THAT(idmap, NotNull());

  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
  ASSERT_EQ(dataBlocks.size(), 1U);

  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];

  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);

  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
  ASSERT_EQ(types.size(), 1U);

  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
  ASSERT_EQ(types[0]->GetEntryCount(), 6U);
  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
  ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/other
  ASSERT_EQ(types[0]->GetEntry(2), kNoEntry);  // string/policy_product
  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_public
  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_system
  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system_vendor
}

TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
// The resources of APKs that do not include an overlayable declaration should not restrict what
// resources can be overlaid.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayable) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  ASSERT_THAT(target_apk, NotNull());

@@ -313,8 +355,7 @@ TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlaya
  std::stringstream error;
  std::unique_ptr<const Idmap> idmap =
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
                           /* enforce_overlayable */ false, error);
                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
  ASSERT_THAT(idmap, NotNull());

  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -340,6 +381,50 @@ TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlaya
  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system_vendor
}

// The resources of APKs that do not include an overlayable declaration should not restrict what
// resources can be overlaid.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
  const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  ASSERT_THAT(target_apk, NotNull());

  const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay-no-name.apk");
  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
  ASSERT_THAT(overlay_apk, NotNull());

  std::stringstream error;
  std::unique_ptr<const Idmap> idmap =
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
  ASSERT_THAT(idmap, NotNull());

  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
  ASSERT_EQ(dataBlocks.size(), 1U);

  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];

  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 2U);

  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
  ASSERT_EQ(types.size(), 2U);

  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x01U);
  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
  ASSERT_EQ(types[0]->GetEntryCount(), 1U);
  ASSERT_EQ(types[0]->GetEntryOffset(), 0U);
  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);

  ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
  ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
  ASSERT_EQ(types[1]->GetEntryCount(), 4U);
  ASSERT_EQ(types[1]->GetEntryOffset(), 9U);
  ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
  ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
  ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
  ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
}

TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
  std::string target_apk_path(GetTestDataPath());
  for (int i = 0; i < 32; i++) {
Loading