diff --git a/init/Android.bp b/init/Android.bp index 6ee9132f5..c7021c3d2 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -283,6 +283,8 @@ cc_binary { static_libs: [ "libbase", "libselinux", + "libpropertyinfoserializer", + "libpropertyinfoparser", ], whole_static_libs: ["libcap"], shared_libs: [ @@ -306,6 +308,7 @@ cc_binary { "host_import_parser.cpp", "host_init_verifier.cpp", "parser.cpp", + "property_type.cpp", "rlimit_parser.cpp", "tokenizer.cpp", "service.cpp", diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp index 9d23921a1..bef6966be 100644 --- a/init/check_builtins.cpp +++ b/init/check_builtins.cpp @@ -29,7 +29,9 @@ #include #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 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 {}; } diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp index 522709e17..3acc3cc97 100644 --- a/init/host_init_verifier.cpp +++ b/init/host_init_verifier.cpp @@ -14,6 +14,8 @@ // limitations under the License. // +#include "host_init_verifier.h" + #include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include #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 passwd_files; @@ -143,11 +150,12 @@ static Result check_stub(const BuiltinArguments& args) { #include "generated_stub_builtin_function_map.h" void PrintUsage() { - std::cout << "usage: host_init_verifier [-p FILE] \n" + std::cout << "usage: host_init_verifier [options] \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 ReadInterfaceInheritanceHierarchy() { return result; } +const PropertyInfoArea* property_info_area; + +void HandlePropertyContexts(const std::string& filename, + std::vector* 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{}; + 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(); + 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(serialized_contexts.c_str()); + const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap(); Action::set_function_map(&function_map); ActionManager& am = ActionManager::GetInstance(); diff --git a/init/host_init_verifier.h b/init/host_init_verifier.h new file mode 100644 index 000000000..5d24f2a9b --- /dev/null +++ b/init/host_init_verifier.h @@ -0,0 +1,27 @@ +/* + * 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 + +namespace android { +namespace init { + +extern const android::properties::PropertyInfoArea* property_info_area; + +} // namespace init +} // namespace android diff --git a/init/property_service.cpp b/init/property_service.cpp index 3baaf7c1f..7d707cc43 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -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;