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

Commit d906d809 authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Android (Google) Code Review
Browse files

Merge "Add enforcement of overlayable targetName"

parents b3c20e6b a362846d
Loading
Loading
Loading
Loading
+13 −35
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"

@@ -36,14 +37,13 @@

using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
using android::idmap2::MemoryChunk;
using android::idmap2::PoliciesToBitmask;
using android::idmap2::PolicyBitmask;
using android::idmap2::PolicyFlags;
using android::idmap2::Result;
using android::idmap2::Xml;
using android::idmap2::ZipFile;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::idmap2::utils::FindFiles;
using android::idmap2::utils::OverlayManifestInfo;

namespace {

@@ -138,46 +138,23 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {

  std::vector<InputOverlay> interesting_apks;
  for (const std::string& path : *apk_paths) {
    std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
    if (!zip) {
      out_error << "error: failed to open " << path << " as a zip file" << std::endl;
    Result<OverlayManifestInfo> overlay_info =
        ExtractOverlayManifestInfo(path, out_error,
                                   /* assert_overlay */ false);
    if (!overlay_info) {
      return false;
    }

    std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
    if (!entry) {
      out_error << "error: failed to uncompress AndroidManifest.xml from " << path << std::endl;
      return false;
    }

    std::unique_ptr<const Xml> xml = Xml::Create(entry->buf, entry->size);
    if (!xml) {
      out_error << "error: failed to parse AndroidManifest.xml from " << path << std::endl;
      continue;
    }

    const auto tag = xml->FindTag("overlay");
    if (!tag) {
      continue;
    }

    auto iter = tag->find("isStatic");
    if (iter == tag->end() || std::stoul(iter->second) == 0U) {
      continue;
    }

    iter = tag->find("targetPackage");
    if (iter == tag->end() || iter->second != target_package_name) {
    if (!overlay_info->is_static) {
      continue;
    }

    iter = tag->find("priority");
    if (iter == tag->end()) {
    if (overlay_info->target_package.empty() ||
        overlay_info->target_package != target_package_name) {
      continue;
    }

    const int priority = std::stoi(iter->second);
    if (priority < 0) {
    if (overlay_info->priority < 0) {
      continue;
    }

@@ -203,7 +180,8 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
    std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);

    // Sort the static overlays in ascending priority order
    InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
    InputOverlay input{path, idmap_path, overlay_info->priority, override_policies,
                       ignore_overlayable};
    interesting_apks.insert(
        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
  }
+14 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
#define IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_

#include <optional>
#include <ostream>
#include <string>

#include "android-base/macros.h"
@@ -24,9 +26,21 @@

#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/ZipFile.h"

namespace android::idmap2::utils {

struct OverlayManifestInfo {
  std::string target_package;  // NOLINT(misc-non-private-member-variables-in-classes)
  std::string target_name;     // NOLINT(misc-non-private-member-variables-in-classes)
  bool is_static;              // NOLINT(misc-non-private-member-variables-in-classes)
  int priority = -1;           // NOLINT(misc-non-private-member-variables-in-classes)
};

Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
                                                       std::ostream& out_error,
                                                       bool assert_overlay = true);

Result<std::string> WARN_UNUSED ResToTypeEntryName(const AssetManager2& am, ResourceId resid);

}  // namespace android::idmap2::utils
+20 −8
Original line number Diff line number Diff line
@@ -274,17 +274,24 @@ std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
  return std::move(idmap);
}

bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices,
                      ResourceId resid) {
  const OverlayableInfo* info = target_package.GetOverlayableInfo(resid);
  if (info == nullptr) {
bool CheckOverlayable(const LoadedPackage& target_package,
                      const utils::OverlayManifestInfo& overlay_info,
                      const PolicyBitmask& fulfilled_polices, const ResourceId& resid) {
  const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
  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;
  }

  if (!overlay_info.target_name.empty() && 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;
  }

  // Enforce policy restrictions if the resource is declared as overlayable.
  return (info->policy_flags & fulfilled_polices) != 0;
  return (overlayable_info->policy_flags & fulfilled_polices) != 0;
}

std::unique_ptr<const Idmap> Idmap::FromApkAssets(
@@ -339,6 +346,12 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(
    return nullptr;
  }

  Result<utils::OverlayManifestInfo> overlay_info =
      utils::ExtractOverlayManifestInfo(overlay_apk_path, out_error);
  if (!overlay_info) {
    return nullptr;
  }

  std::unique_ptr<IdmapHeader> header(new IdmapHeader());
  header->magic_ = kIdmapMagic;
  header->version_ = kIdmapCurrentVersion;
@@ -393,9 +406,8 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(
      continue;
    }

    if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) {
      // The resources must be defined as overlayable and the overlay must fulfill at least one
      // policy enforced on the overlayable resource
    if (enforce_overlayable &&
        !CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid)) {
      LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
                   << full_name << "\"" << std::endl;
      continue;
+65 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 * limitations under the License.
 */

#include <memory>
#include <string>

#include "androidfw/StringPiece.h"
@@ -21,8 +22,13 @@

#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"

using android::StringPiece16;
using android::idmap2::Result;
using android::idmap2::Xml;
using android::idmap2::ZipFile;
using android::util::Utf16ToUtf8;

namespace android::idmap2::utils {
@@ -47,4 +53,63 @@ Result<std::string> WARN_UNUSED ResToTypeEntryName(const AssetManager2& am, Reso
  return {out};
}

Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
                                                       std::ostream& out_error,
                                                       bool assert_overlay) {
  std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
  if (!zip) {
    out_error << "error: failed to open " << path << " as a zip file" << std::endl;
    return kResultError;
  }

  std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
  if (!entry) {
    out_error << "error: failed to uncompress AndroidManifest.xml from " << path << std::endl;
    return kResultError;
  }

  std::unique_ptr<const Xml> xml = Xml::Create(entry->buf, entry->size);
  if (!xml) {
    out_error << "error: failed to parse AndroidManifest.xml from " << path << std::endl;
    return kResultError;
  }

  OverlayManifestInfo info{};
  const auto tag = xml->FindTag("overlay");
  if (!tag) {
    if (assert_overlay) {
      out_error << "error: <overlay> missing from AndroidManifest.xml of " << path << std::endl;
      return kResultError;
    }
    return info;
  }

  auto iter = tag->find("targetPackage");
  if (iter == tag->end()) {
    if (assert_overlay) {
      out_error << "error: android:targetPackage missing from <overlay> of " << path << std::endl;
      return kResultError;
    }
  } else {
    info.target_package = iter->second;
  }

  iter = tag->find("targetName");
  if (iter != tag->end()) {
    info.target_name = iter->second;
  }

  iter = tag->find("isStatic");
  if (iter != tag->end()) {
    info.is_static = std::stoul(iter->second) != 0U;
  }

  iter = tag->find("priority");
  if (iter != tag->end()) {
    info.priority = std::stoi(iter->second);
  }

  return info;
}

}  // namespace android::idmap2::utils
+15 −12
Original line number Diff line number Diff line
@@ -111,43 +111,46 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) {
  success = LoadedIdmap::Lookup(header, 0x0002, &entry);  // string/c
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/not_overlayable
  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/other
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/policy_product
  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/not_overlayable
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_public
  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_product
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_system
  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_public
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system_vendor
  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/str1
  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/policy_system_vendor
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/str1
  ASSERT_TRUE(success);
  ASSERT_EQ(entry, 0x0000);

  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/str2
  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str2
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str3
  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str3
  ASSERT_TRUE(success);
  ASSERT_EQ(entry, 0x0001);

  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str4
  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/str4
  ASSERT_TRUE(success);
  ASSERT_EQ(entry, 0x0002);

  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/x
  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/x
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/y
  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/y
  ASSERT_FALSE(success);

  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/z
  success = LoadedIdmap::Lookup(header, 0x000f, &entry);  // string/z
  ASSERT_FALSE(success);
}

Loading