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

Commit d10d06d0 authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Ryan Mitchell
Browse files

Add enforcement of idmap policies



Teaches idmap2 to recognize policy restrictions put on overlayable
resources. If overlayable enforcement is turned on for an overlay, then
any resources defined within the overlayable api of the target will have
policy restrictions imposed on them. All resources without overlayable
definitions will continue to be overlayable without policy restrictions.

Bug: 119390857
Test: atest idmap2 and booting

Co-authored-by: default avatarRyan Mitchell <rtmitchell@google.com>
Change-Id: I7e435648eb6e4a87b0b90a7b2a0c3f33c1516ea6
parent f9d10621
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ cc_library {
        "libidmap2/CommandLineOptions.cpp",
        "libidmap2/FileUtils.cpp",
        "libidmap2/Idmap.cpp",
        "libidmap2/Policies.cpp",
        "libidmap2/PrettyPrintVisitor.cpp",
        "libidmap2/RawPrintVisitor.cpp",
        "libidmap2/ResourceUtils.cpp",
@@ -87,6 +88,7 @@ cc_test {
        "tests/Idmap2BinaryTests.cpp",
        "tests/IdmapTests.cpp",
        "tests/Main.cpp",
        "tests/PoliciesTests.cpp",
        "tests/PrettyPrintVisitorTests.cpp",
        "tests/RawPrintVisitorTests.cpp",
        "tests/ResourceUtilsTests.cpp",
+28 −3
Original line number Diff line number Diff line
@@ -27,17 +27,25 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
#include "idmap2/Result.h"

using android::ApkAssets;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
using android::idmap2::PoliciesToBitmask;
using android::idmap2::PolicyBitmask;
using android::idmap2::PolicyFlags;
using android::idmap2::Result;
using android::idmap2::utils::kIdmapFilePermissionMask;

bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
  std::string target_apk_path;
  std::string overlay_apk_path;
  std::string idmap_path;
  std::vector<std::string> policies;
  bool ignore_overlayable;

  const CommandLineOptions opts =
      CommandLineOptions("idmap2 create")
@@ -47,12 +55,28 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
          .MandatoryOption("--overlay-apk-path",
                           "input: path to apk which contains the new resource values",
                           &overlay_apk_path)
          .MandatoryOption("--idmap-path", "output: path to where to write idmap file",
                           &idmap_path);
          .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
          .OptionalOption("--policy",
                          "input: an overlayable policy this overlay fulfills "
                          "(if none or supplied, the overlay policy will default to \"public\")",
                          &policies)
          .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
                        &ignore_overlayable);
  if (!opts.Parse(args, out_error)) {
    return false;
  }

  PolicyBitmask fulfilled_policies = 0;
  if (auto result = PoliciesToBitmask(policies, out_error)) {
    fulfilled_policies |= *result;
  } else {
    return false;
  }

  if (fulfilled_policies == 0) {
    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
  }

  const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  if (!target_apk) {
    out_error << "error: failed to load apk " << target_apk_path << std::endl;
@@ -66,7 +90,8 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
  }

  const std::unique_ptr<const Idmap> idmap =
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
                           fulfilled_policies, !ignore_overlayable, out_error);
  if (!idmap) {
    return false;
  }
+89 −18
Original line number Diff line number Diff line
@@ -21,8 +21,11 @@
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "android-base/properties.h"

#include "idmap2/CommandLineOptions.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
@@ -34,6 +37,10 @@
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::FindFiles;
@@ -48,8 +55,16 @@ struct InputOverlay {
  std::string apk_path;               // NOLINT(misc-non-private-member-variables-in-classes)
  std::string idmap_path;             // NOLINT(misc-non-private-member-variables-in-classes)
  int priority;                       // NOLINT(misc-non-private-member-variables-in-classes)
  std::vector<std::string> policies;  // NOLINT(misc-non-private-member-variables-in-classes)
  bool ignore_overlayable;            // NOLINT(misc-non-private-member-variables-in-classes)
};

bool VendorIsQOrLater() {
  // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
  std::string version = android::base::GetProperty("ro.vndk.version", "Q");
  return version == "Q" || version == "q";
}

std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                       bool recursive, std::ostream& out_error) {
  const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -70,6 +85,22 @@ std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::st
  return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
}

PolicyBitmask PolicyForPath(const std::string& apk_path) {
  static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
      {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
      {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
      {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
  };

  for (auto const& pair : values) {
    if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
      return pair.second | PolicyFlags::POLICY_PUBLIC;
    }
  }

  return PolicyFlags::POLICY_PUBLIC;
}

}  // namespace

bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -77,6 +108,7 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
  std::string target_package_name;
  std::string target_apk_path;
  std::string output_directory;
  std::vector<std::string> override_policies;
  bool recursive = false;

  const CommandLineOptions opts =
@@ -89,7 +121,12 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
          .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
          .MandatoryOption("--output-directory",
                           "directory in which to write artifacts (idmap files and overlays.list)",
                           &output_directory);
                           &output_directory)
          .OptionalOption(
              "--override-policy",
              "input: an overlayable policy this overlay fulfills "
              "(if none or supplied, the overlays will not have their policies overriden",
              &override_policies);
  if (!opts.Parse(args, out_error)) {
    return false;
  }
@@ -144,28 +181,62 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
      continue;
    }

    // Sort the static overlays in ascending priority order
    PolicyBitmask fulfilled_policies;
    if (!override_policies.empty()) {
      if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
        fulfilled_policies = *result;
      } else {
        return false;
      }
    } else {
      fulfilled_policies = PolicyForPath(path);
    }

    bool ignore_overlayable = false;
    if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
      // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
      // restrictions on this overlay because the pre-Q platform has no understanding of
      // overlayable.
      ignore_overlayable = true;
    }

    std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
    InputOverlay input{path, idmap_path, priority};

    // Sort the static overlays in ascending priority order
    InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
    interesting_apks.insert(
        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
  }

  std::stringstream stream;
  for (const auto& overlay : interesting_apks) {
    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
    std::stringstream dev_null;
    if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
        !Create(std::vector<std::string>({
                    "--target-apk-path",
                    target_apk_path,
                    "--overlay-apk-path",
                    overlay.apk_path,
                    "--idmap-path",
                    overlay.idmap_path,
                }),
                out_error)) {

    std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
    for (const std::string& policy : overlay.policies) {
      verify_args.emplace_back("--policy");
      verify_args.emplace_back(policy);
    }

    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
      std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
                                              "--overlay-apk-path", overlay.apk_path,
                                              "--idmap-path",       overlay.idmap_path};
      if (overlay.ignore_overlayable) {
        create_args.emplace_back("--ignore-overlayable");
      }

      for (const std::string& policy : overlay.policies) {
        verify_args.emplace_back("--policy");
        verify_args.emplace_back(policy);
      }

      if (!Create(create_args, out_error)) {
        return false;
      }
    }

    stream << overlay.idmap_path << std::endl;
  }

+20 −2
Original line number Diff line number Diff line
@@ -26,12 +26,15 @@
#include <string>

#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "utils/String8.h"
#include "utils/Trace.h"

#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
#include "idmap2/Result.h"

#include "idmap2d/Idmap2Service.h"

@@ -39,6 +42,8 @@ using android::binder::Status;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
using android::idmap2::PolicyBitmask;
using android::idmap2::Result;
using android::idmap2::utils::kIdmapFilePermissionMask;

namespace {
@@ -54,6 +59,10 @@ Status error(const std::string& msg) {
  return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
}

PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
  return static_cast<PolicyBitmask>(arg);
}

}  // namespace

namespace android::os {
@@ -78,6 +87,8 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
}

Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
                                  int32_t fulfilled_policies ATTRIBUTE_UNUSED,
                                  bool enforce_overlayable ATTRIBUTE_UNUSED,
                                  int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
  assert(_aidl_return);
  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -86,11 +97,15 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
  fin.close();
  std::stringstream dev_null;
  *_aidl_return = header && header->IsUpToDate(dev_null);

  // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed

  return ok();
}

Status Idmap2Service::createIdmap(const std::string& target_apk_path,
                                  const std::string& overlay_apk_path, int32_t user_id,
                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
                                  bool enforce_overlayable, int32_t user_id,
                                  std::unique_ptr<std::string>* _aidl_return) {
  assert(_aidl_return);
  std::stringstream trace;
@@ -101,6 +116,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,

  _aidl_return->reset(nullptr);

  const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);

  const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
  if (!target_apk) {
    return error("failed to load apk " + target_apk_path);
@@ -113,7 +130,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,

  std::stringstream err;
  const std::unique_ptr<const Idmap> idmap =
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
                           policy_bitmask, enforce_overlayable, err);
  if (!idmap) {
    return error(err.str());
  }
+4 −3
Original line number Diff line number Diff line
@@ -39,11 +39,12 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
  binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
                             bool* _aidl_return);

  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
                             bool* _aidl_return);
  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
                             bool enforce_overlayable, int32_t user_id, bool* _aidl_return);

  binder::Status createIdmap(const std::string& target_apk_path,
                             const std::string& overlay_apk_path, int32_t user_id,
                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
                             bool enforce_overlayable, int32_t user_id,
                             std::unique_ptr<std::string>* _aidl_return);
};

Loading