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:
parent
1d284004af
commit
b5f2ec06f5
5 changed files with 92 additions and 3 deletions
|
@ -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",
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
27
init/host_init_verifier.h
Normal 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
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue