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

Commit 314863c1 authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Gerrit Code Review
Browse files

Merge changes from topic "inc-hard-am"

* changes:
  Revert^2 "Cache resolved theme values"
  Set resource id correctly when resolve fails
  Revert^2 "libandroidfw hardening for IncFs"
  idmap2: remove call to obsolete 'idmap2 verify' from valgrind.sh
  idmap2: remove the 'scan' command
parents 2991744d a45506e6
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -181,7 +181,6 @@ cc_binary {
        "idmap2/Dump.cpp",
        "idmap2/Lookup.cpp",
        "idmap2/Main.cpp",
        "idmap2/Scan.cpp",
    ],
    target: {
        android: {
+0 −1
Original line number Diff line number Diff line
@@ -26,6 +26,5 @@ android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::str
android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);

#endif  // IDMAP2_IDMAP2_COMMANDS_H_
+25 −46
Original line number Diff line number Diff line
@@ -45,11 +45,8 @@ using android::ApkAssets;
using android::ApkAssetsCookie;
using android::AssetManager2;
using android::ConfigDescription;
using android::is_valid_resid;
using android::kInvalidCookie;
using android::Res_value;
using android::ResStringPool;
using android::ResTable_config;
using android::StringPiece16;
using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
@@ -59,7 +56,6 @@ using android::idmap2::ResourceId;
using android::idmap2::Result;
using android::idmap2::Unit;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::util::Utf16ToUtf8;

namespace {

@@ -69,25 +65,23 @@ Result<ResourceId> WARN_UNUSED ParseResReference(const AssetManager2& am, const

  // first, try to parse as a hex number
  char* endptr = nullptr;
  ResourceId resid;
  resid = strtol(res.c_str(), &endptr, kBaseHex);
  const ResourceId parsed_resid = strtol(res.c_str(), &endptr, kBaseHex);
  if (*endptr == '\0') {
    return resid;
    return parsed_resid;
  }

  // next, try to parse as a package:type/name string
  resid = am.GetResourceId(res, "", fallback_package);
  if (is_valid_resid(resid)) {
    return resid;
  if (auto resid = am.GetResourceId(res, "", fallback_package)) {
    return *resid;
  }

  // end of the road: res could not be parsed
  return Error("failed to obtain resource id for %s", res.c_str());
}

void PrintValue(AssetManager2* const am, const Res_value& value, const ApkAssetsCookie& cookie,
void PrintValue(AssetManager2* const am, const AssetManager2::SelectedValue& value,
                std::string* const out) {
  switch (value.dataType) {
  switch (value.type) {
    case Res_value::TYPE_INT_DEC:
      out->append(StringPrintf("%d", value.data));
      break;
@@ -98,30 +92,21 @@ void PrintValue(AssetManager2* const am, const Res_value& value, const ApkAssets
      out->append(value.data != 0 ? "true" : "false");
      break;
    case Res_value::TYPE_STRING: {
      const ResStringPool* pool = am->GetStringPoolForCookie(cookie);
      const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
      out->append("\"");
      size_t len;
      if (pool->isUTF8()) {
        const char* str = pool->string8At(value.data, &len);
        out->append(str, len);
      } else {
        const char16_t* str16 = pool->stringAt(value.data, &len);
        out->append(Utf16ToUtf8(StringPiece16(str16, len)));
      if (auto str = pool->string8ObjectAt(value.data)) {
        out->append(*str);
      }
      out->append("\"");
    } break;
    default:
      out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
      out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.type, value.data));
      break;
  }
}

Result<std::string> WARN_UNUSED GetValue(AssetManager2* const am, ResourceId resid) {
  Res_value value;
  ResTable_config config;
  uint32_t flags;
  ApkAssetsCookie cookie = am->GetResource(resid, true, 0, &value, &config, &flags);
  if (cookie == kInvalidCookie) {
  auto value = am->GetResource(resid);
  if (!value.has_value()) {
    return Error("no resource 0x%08x in asset manager", resid);
  }

@@ -129,41 +114,35 @@ Result<std::string> WARN_UNUSED GetValue(AssetManager2* const am, ResourceId res

  // TODO(martenkongstad): use optional parameter GetResource(..., std::string*
  // stacktrace = NULL) instead
  out.append(StringPrintf("cookie=%d ", cookie));
  out.append(StringPrintf("cookie=%d ", value->cookie));

  out.append("config='");
  out.append(config.toString().c_str());
  out.append(value->config.toString().c_str());
  out.append("' value=");

  if (value.dataType == Res_value::TYPE_REFERENCE) {
    const android::ResolvedBag* bag = am->GetBag(static_cast<uint32_t>(value.data));
    if (bag == nullptr) {
      out.append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
  if (value->type == Res_value::TYPE_REFERENCE) {
    auto bag_result = am->GetBag(static_cast<uint32_t>(value->data));
    if (!bag_result.has_value()) {
      out.append(StringPrintf("dataType=0x%02x data=0x%08x", value->type, value->data));
      return out;
    }

    out.append("[");
    Res_value bag_val;
    ResTable_config selected_config;
    uint32_t flags;
    uint32_t ref;
    ApkAssetsCookie bag_cookie;
    const android::ResolvedBag* bag = bag_result.value();
    for (size_t i = 0; i < bag->entry_count; ++i) {
      const android::ResolvedBag::Entry& entry = bag->entries[i];
      bag_val = entry.value;
      bag_cookie = am->ResolveReference(entry.cookie, &bag_val, &selected_config, &flags, &ref);
      if (bag_cookie == kInvalidCookie) {
        out.append(
            StringPrintf("Error: dataType=0x%02x data=0x%08x", bag_val.dataType, bag_val.data));
      AssetManager2::SelectedValue entry(bag, bag->entries[i]);
      if (am->ResolveReference(entry).has_value()) {
        out.append(StringPrintf("Error: dataType=0x%02x data=0x%08x", entry.type, entry.data));
        continue;
      }
      PrintValue(am, bag_val, bag_cookie, &out);
      PrintValue(am, entry, &out);
      if (i != bag->entry_count - 1) {
        out.append(", ");
      }
    }
    out.append("]");
  } else {
    PrintValue(am, value, cookie, &out);
    PrintValue(am, *value, &out);
  }

  return out;
+4 −2
Original line number Diff line number Diff line
@@ -53,8 +53,10 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
int main(int argc, char** argv) {
  SYSTRACE << "main";
  const NameToFunctionMap commands = {
      {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup},
      {"scan", Scan},
      {"create", Create},
      {"create-multiple", CreateMultiple},
      {"dump", Dump},
      {"lookup", Lookup},
  };
  if (argc <= 1) {
    PrintUsage(commands, std::cerr);

cmds/idmap2/idmap2/Scan.cpp

deleted100644 → 0
+0 −257
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <dirent.h>

#include <fstream>
#include <memory>
#include <ostream>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "Commands.h"
#include "android-base/properties.h"
#include "idmap2/CommandLineOptions.h"
#include "idmap2/CommandUtils.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "idmap2/XmlParser.h"

using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::Idmap;
using android::idmap2::Result;
using android::idmap2::Unit;
using android::idmap2::policy::kPolicyOdm;
using android::idmap2::policy::kPolicyOem;
using android::idmap2::policy::kPolicyProduct;
using android::idmap2::policy::kPolicyPublic;
using android::idmap2::policy::kPolicySystem;
using android::idmap2::policy::kPolicyVendor;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::idmap2::utils::FindFiles;
using android::idmap2::utils::OverlayManifestInfo;
using android::idmap2::utils::PoliciesToBitmaskResult;

using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;

namespace {

struct InputOverlay {
  bool operator<(InputOverlay const& rhs) const {
    return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
  }

  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() {
  constexpr int kQSdkVersion = 29;
  constexpr int kBase = 10;
  std::string version_prop = android::base::GetProperty("ro.vndk.version", "29");
  int version = strtol(version_prop.data(), nullptr, kBase);

  // If the string cannot be parsed, it is a development sdk codename.
  return version >= kQSdkVersion || version == 0;
}

Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
                                                               bool recursive) {
  SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
  const auto predicate = [](unsigned char type, const std::string& path) -> bool {
    static constexpr size_t kExtLen = 4;  // strlen(".apk")
    return type == DT_REG && path.size() > kExtLen &&
           path.compare(path.size() - kExtLen, kExtLen, ".apk") == 0;
  };
  // pass apk paths through a set to filter out duplicates
  std::set<std::string> paths;
  for (const auto& dir : dirs) {
    const auto apk_paths = FindFiles(dir, recursive, predicate);
    if (!apk_paths) {
      return Error("failed to open directory %s", dir.c_str());
    }
    paths.insert(apk_paths->cbegin(), apk_paths->cend());
  }
  return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
}

std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
  // clang-format off
  static const std::vector<std::pair<std::string, std::string>> values = {
      {"/odm/", kPolicyOdm},
      {"/oem/", kPolicyOem},
      {"/product/", kPolicyProduct},
      {"/system/", kPolicySystem},
      {"/system_ext/", kPolicySystem},
      {"/vendor/", kPolicyVendor},
  };
  // clang-format on

  std::vector<std::string> fulfilled_policies = {kPolicyPublic};
  for (auto const& pair : values) {
    if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
      fulfilled_policies.emplace_back(pair.second);
      break;
    }
  }

  return fulfilled_policies;
}

}  // namespace

Result<Unit> Scan(const std::vector<std::string>& args) {
  SYSTRACE << "Scan " << args;
  std::vector<std::string> input_directories;
  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 =
      CommandLineOptions("idmap2 scan")
          .MandatoryOption("--input-directory", "directory containing overlay apks to scan",
                           &input_directories)
          .OptionalFlag("--recursive", "also scan subfolders of overlay-directory", &recursive)
          .MandatoryOption("--target-package-name", "package name of target package",
                           &target_package_name)
          .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)
          .OptionalOption(
              "--override-policy",
              "input: an overlayable policy this overlay fulfills "
              "(if none or supplied, the overlays will not have their policies overriden",
              &override_policies);
  const auto opts_ok = opts.Parse(args);
  if (!opts_ok) {
    return opts_ok.GetError();
  }

  const auto apk_paths = FindApkFiles(input_directories, recursive);
  if (!apk_paths) {
    return Error(apk_paths.GetError(), "failed to find apk files");
  }

  std::vector<InputOverlay> interesting_apks;
  for (const std::string& path : **apk_paths) {
    Result<OverlayManifestInfo> overlay_info =
        ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
    if (!overlay_info) {
      return overlay_info.GetError();
    }

    if (!overlay_info->is_static) {
      continue;
    }

    if (overlay_info->target_package.empty() ||
        overlay_info->target_package != target_package_name) {
      continue;
    }

    if (overlay_info->priority < 0) {
      continue;
    }

    // Note that conditional property enablement/exclusion only applies if
    // the attribute is present. In its absence, all overlays are presumed enabled.
    if (!overlay_info->requiredSystemPropertyName.empty() &&
        !overlay_info->requiredSystemPropertyValue.empty()) {
      // if property set & equal to value, then include overlay - otherwise skip
      if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") !=
          overlay_info->requiredSystemPropertyValue) {
        continue;
      }
    }

    std::vector<std::string> fulfilled_policies;
    if (!override_policies.empty()) {
      fulfilled_policies = override_policies;
    } else {
      fulfilled_policies = PoliciesForPath(path);
    }

    bool ignore_overlayable = false;
    if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) !=
            fulfilled_policies.end() &&
        !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);

    // Sort the static overlays in ascending priority order
    InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_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) {
    const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies);
    if (!policy_bitmask) {
      LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
                   << "\": " << policy_bitmask.GetErrorMessage();
      continue;
    }

    if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask,
                !overlay.ignore_overlayable)) {
      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) {
        create_args.emplace_back("--policy");
        create_args.emplace_back(policy);
      }

      const auto create_ok = Create(create_args);
      if (!create_ok) {
        LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
                     << "\": " << create_ok.GetError().GetMessage();
        continue;
      }
    }

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

  std::cout << stream.str();

  return Unit{};
}
Loading