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

Commit cf539f16 authored by Daniel Norman's avatar Daniel Norman Committed by Gerrit Code Review
Browse files

Merge "Returns a service parse error on overrides across the treble boundary."

parents 7cf47025 f597fa5d
Loading
Loading
Loading
Loading
+70 −16
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <string>
#include <vector>

@@ -51,6 +53,7 @@

using namespace std::literals;

using android::base::EndsWith;
using android::base::ParseInt;
using android::base::ReadFileToString;
using android::base::Split;
@@ -61,6 +64,10 @@ using android::properties::PropertyInfoEntry;

static std::vector<std::string> passwd_files;

// NOTE: Keep this in sync with the order used by init.cpp LoadBootScripts()
static const std::vector<std::string> partition_search_order =
        std::vector<std::string>({"system", "system_ext", "odm", "vendor", "product"});

static std::vector<std::pair<std::string, int>> GetVendorPasswd(const std::string& passwd_file) {
    std::string passwd;
    if (!ReadFileToString(passwd_file, &passwd)) {
@@ -148,13 +155,24 @@ static Result<void> check_stub(const BuiltinArguments& args) {
#include "generated_stub_builtin_function_map.h"

void PrintUsage() {
    std::cout << "usage: host_init_verifier [options] <init rc file>\n"
                 "\n"
                 "Tests an init script for correctness\n"
                 "\n"
                 "-p FILE\tSearch this passwd file for users and groups\n"
                 "--property_contexts=FILE\t Use this file for property_contexts\n"
              << std::endl;
    fprintf(stdout, R"(usage: host_init_verifier [options]

Tests init script(s) for correctness.

Generic options:
  -p FILE                     Search this passwd file for users and groups.
  --property_contexts=FILE    Use this file for property_contexts.

Single script mode options:
  [init rc file]              Positional argument; test this init script.

Multiple script mode options:
  --out_system=DIR            Path to the output product directory for the system partition.
  --out_system_ext=DIR        Path to the output product directory for the system_ext partition.
  --out_odm=DIR               Path to the output product directory for the odm partition.
  --out_vendor=DIR            Path to the output product directory for the vendor partition.
  --out_product=DIR           Path to the output product directory for the product partition.
)");
}

Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy() {
@@ -203,12 +221,18 @@ int main(int argc, char** argv) {
    android::base::SetMinimumLogSeverity(android::base::ERROR);

    auto property_infos = std::vector<PropertyInfoEntry>();
    std::map<std::string, std::string> partition_map;

    while (true) {
        static const char kPropertyContexts[] = "property-contexts=";
        static const struct option long_options[] = {
                {"help", no_argument, nullptr, 'h'},
                {kPropertyContexts, required_argument, nullptr, 0},
                {"out_system", required_argument, nullptr, 0},
                {"out_system_ext", required_argument, nullptr, 0},
                {"out_odm", required_argument, nullptr, 0},
                {"out_vendor", required_argument, nullptr, 0},
                {"out_product", required_argument, nullptr, 0},
                {nullptr, 0, nullptr, 0},
        };

@@ -224,6 +248,16 @@ int main(int argc, char** argv) {
                if (long_options[option_index].name == kPropertyContexts) {
                    HandlePropertyContexts(optarg, &property_infos);
                }
                for (const auto& p : partition_search_order) {
                    if (long_options[option_index].name == "out_" + p) {
                        if (partition_map.find(p) != partition_map.end()) {
                            PrintUsage();
                            return EXIT_FAILURE;
                        }
                        partition_map[p] =
                                EndsWith(optarg, "/") ? optarg : std::string(optarg) + "/";
                    }
                }
                break;
            case 'h':
                PrintUsage();
@@ -240,7 +274,9 @@ int main(int argc, char** argv) {
    argc -= optind;
    argv += optind;

    if (argc != 1) {
    // If provided, use the partition map to check multiple init rc files.
    // Otherwise, check a single init rc file.
    if ((!partition_map.empty() && argc != 0) || (partition_map.empty() && argc != 1)) {
        PrintUsage();
        return EXIT_FAILURE;
    }
@@ -262,24 +298,42 @@ int main(int argc, char** argv) {

    property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_contexts.c_str());

    if (!partition_map.empty()) {
        std::vector<std::string> vendor_prefixes;
        for (const auto& partition : {"vendor", "odm"}) {
            if (partition_map.find(partition) != partition_map.end()) {
                vendor_prefixes.push_back(partition_map.at(partition));
            }
        }
        InitializeHostSubcontext(vendor_prefixes);
    }

    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sl = ServiceList::GetInstance();
    Parser parser;
    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
                                               &sl, nullptr, *interface_inheritance_hierarchy_map));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
    parser.AddSectionParser("service",
                            std::make_unique<ServiceParser>(&sl, GetSubcontext(),
                                                            *interface_inheritance_hierarchy_map));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, GetSubcontext()));
    parser.AddSectionParser("import", std::make_unique<HostImportParser>());

    if (!partition_map.empty()) {
        for (const auto& p : partition_search_order) {
            if (partition_map.find(p) != partition_map.end()) {
                parser.ParseConfig(partition_map.at(p) + "etc/init");
            }
        }
    } else {
        if (!parser.ParseConfigFileInsecure(*argv)) {
            LOG(ERROR) << "Failed to open init rc script '" << *argv << "'";
            return EXIT_FAILURE;
        }
    }
    size_t failures = parser.parse_error_count() + am.CheckAllCommands() + sl.CheckAllCommands();
    if (failures > 0) {
        LOG(ERROR) << "Failed to parse init script '" << *argv << "' with " << failures
                   << " errors";
        LOG(ERROR) << "Failed to parse init scripts with " << failures << " error(s).";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
                 .priority = 0},
      namespaces_{.flags = namespace_flags},
      seclabel_(seclabel),
      subcontext_(subcontext_for_restart_commands),
      onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
                 "onrestart", {}),
      oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
+2 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ class Service {
            flags_ &= ~SVC_ONESHOT;
        }
    }
    Subcontext* subcontext() const { return subcontext_; }

  private:
    void NotifyStateChange(const std::string& new_state) const;
@@ -168,6 +169,7 @@ class Service {
    std::vector<FileDescriptor> files_;
    std::vector<std::pair<std::string, std::string>> environment_vars_;

    Subcontext* subcontext_;
    Action onrestart_;  // Commands to execute on restart.

    std::vector<std::string> writepid_files_;
+8 −0
Original line number Diff line number Diff line
@@ -657,6 +657,14 @@ Result<void> ServiceParser::EndSection() {
                           << "' with a config in APEX";
        }

        std::string context = service_->subcontext() ? service_->subcontext()->context() : "";
        std::string old_context =
                old_service->subcontext() ? old_service->subcontext()->context() : "";
        if (context != old_context) {
            return Error() << "service '" << service_->name() << "' overrides another service "
                           << "across the treble boundary.";
        }

        service_list_->RemoveService(*old_service);
        old_service = nullptr;
    }
+3 −0
Original line number Diff line number Diff line
@@ -342,6 +342,9 @@ void InitializeSubcontext() {
                new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
    }
}
void InitializeHostSubcontext(std::vector<std::string> vendor_prefixes) {
    subcontext.reset(new Subcontext(vendor_prefixes, kVendorContext, /*host=*/true));
}

Subcontext* GetSubcontext() {
    return subcontext.get();
Loading