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

Commit b5f2ec06 authored by Tom Cherry's avatar Tom Cherry
Browse files

init: check property type in host_init_verifier

We have all of the 'type' information for properties available during
build time, so let's check this when setting properties in init.

Test: setprop apexd.status bad results in:
host_init_verifier: Command 'setprop apexd.status bad'
(out/soong/.intermediates/system/core/rootdir/init.rc/android_x86_core/init.rc:927)
failed: Property type check failed, value doesn't match expected type
'enum starting ready'
host_init_verifier: Failed to parse init script
'out/soong/.intermediates/system/core/rootdir/init.rc/android_x86_core/init.rc'
with 1 errors
Test: CF builds without that error

Change-Id: Iaad07747c09f4a10b2b816c455d6e8a485357ab9
parent 1d284004
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -281,6 +281,8 @@ cc_binary {
    static_libs: [
        "libbase",
        "libselinux",
        "libpropertyinfoserializer",
        "libpropertyinfoparser",
    ],
    whole_static_libs: ["libcap"],
    shared_libs: [
@@ -304,6 +306,7 @@ cc_binary {
        "host_import_parser.cpp",
        "host_init_verifier.cpp",
        "parser.cpp",
        "property_type.cpp",
        "rlimit_parser.cpp",
        "tokenizer.cpp",
        "service.cpp",
+11 −0
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@
#include <android-base/strings.h>

#include "builtin_arguments.h"
#include "host_init_verifier.h"
#include "interface_utils.h"
#include "property_type.h"
#include "rlimit_parser.h"
#include "service.h"
#include "util.h"
@@ -171,6 +173,15 @@ Result<void> check_setprop(const BuiltinArguments& args) {
                       << "' from init; use the restorecon builtin directly";
    }

    const char* target_context = nullptr;
    const char* type = nullptr;
    property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);

    if (!CheckType(type, value)) {
        return Error() << "Property type check failed, value doesn't match expected type '"
                       << (type ?: "(null)") << "'";
    }

    return {};
}

+50 −2
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
// limitations under the License.
//

#include "host_init_verifier.h"

#include <errno.h>
#include <getopt.h>
#include <pwd.h>
@@ -31,6 +33,7 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <hidl/metadata.h>
#include <property_info_serializer/property_info_serializer.h>

#include "action.h"
#include "action_manager.h"
@@ -53,6 +56,10 @@ using namespace std::literals;
using android::base::ParseInt;
using android::base::ReadFileToString;
using android::base::Split;
using android::properties::BuildTrie;
using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoArea;
using android::properties::PropertyInfoEntry;

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

@@ -143,11 +150,12 @@ static Result<void> check_stub(const BuiltinArguments& args) {
#include "generated_stub_builtin_function_map.h"

void PrintUsage() {
    std::cout << "usage: host_init_verifier [-p FILE] <init rc file>\n"
    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;
}

@@ -172,23 +180,53 @@ Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy() {
    return result;
}

const PropertyInfoArea* property_info_area;

void HandlePropertyContexts(const std::string& filename,
                            std::vector<PropertyInfoEntry>* property_infos) {
    auto file_contents = std::string();
    if (!ReadFileToString(filename, &file_contents)) {
        PLOG(ERROR) << "Could not read properties from '" << filename << "'";
        exit(EXIT_FAILURE);
    }

    auto errors = std::vector<std::string>{};
    ParsePropertyInfoFile(file_contents, property_infos, &errors);
    for (const auto& error : errors) {
        LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
    }
    if (!errors.empty()) {
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char** argv) {
    android::base::InitLogging(argv, &android::base::StdioLogger);
    android::base::SetMinimumLogSeverity(android::base::ERROR);

    auto property_infos = std::vector<PropertyInfoEntry>();

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

        int arg = getopt_long(argc, argv, "p:", long_options, nullptr);
        int option_index;
        int arg = getopt_long(argc, argv, "p:", long_options, &option_index);

        if (arg == -1) {
            break;
        }

        switch (arg) {
            case 0:
                if (long_options[option_index].name == kPropertyContexts) {
                    HandlePropertyContexts(optarg, &property_infos);
                }
                break;
            case 'h':
                PrintUsage();
                return EXIT_FAILURE;
@@ -216,6 +254,16 @@ int main(int argc, char** argv) {
    }
    SetKnownInterfaces(*interface_inheritance_hierarchy_map);

    std::string serialized_contexts;
    std::string trie_error;
    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
                   &trie_error)) {
        LOG(ERROR) << "Unable to serialize property contexts: " << trie_error;
        return EXIT_FAILURE;
    }

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

    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);
    ActionManager& am = ActionManager::GetInstance();
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#pragma once

#include <property_info_parser/property_info_parser.h>

namespace android {
namespace init {

extern const android::properties::PropertyInfoArea* property_info_area;

}  // namespace init
}  // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ uint32_t CheckPermissions(const std::string& name, const std::string& value,
        return PROP_ERROR_PERMISSION_DENIED;
    }

    if (type == nullptr || !CheckType(type, value)) {
    if (!CheckType(type, value)) {
        *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
                              (type ?: "(null)"));
        return PROP_ERROR_INVALID_VALUE;