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
This commit is contained in:
Tom Cherry 2019-11-08 17:54:27 -08:00
parent 1d284004af
commit b5f2ec06f5
5 changed files with 92 additions and 3 deletions

View file

@ -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",

View file

@ -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 {};
}

View file

@ -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
init/host_init_verifier.h Normal file
View file

@ -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 <property_info_parser/property_info_parser.h>
namespace android {
namespace init {
extern const android::properties::PropertyInfoArea* property_info_area;
} // namespace init
} // namespace android

View file

@ -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;