Merge "init: clean up the 1st/2nd stage init split"

This commit is contained in:
Tom Cherry 2018-11-29 16:50:37 +00:00 committed by Gerrit Code Review
commit 3ecaf2e7f5
10 changed files with 167 additions and 96 deletions

View file

@ -79,6 +79,7 @@ cc_defaults {
"libkeyutils",
"liblog",
"liblogwrap",
"liblp",
"libselinux",
"libutils",
],
@ -99,6 +100,7 @@ cc_library_static {
"devices.cpp",
"epoll.cpp",
"firmware_handler.cpp",
"first_stage_init.cpp",
"first_stage_mount.cpp",
"import_parser.cpp",
"init.cpp",
@ -117,6 +119,7 @@ cc_library_static {
"sigchld_handler.cpp",
"subcontext.cpp",
"subcontext.proto",
"switch_root.cpp",
"rlimit_parser.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",

View file

@ -39,12 +39,15 @@ init_cflags += \
# --
# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES := \
devices.cpp \
first_stage_init.cpp \
first_stage_main.cpp \
first_stage_mount.cpp \
init_first_stage.cpp \
reboot_utils.cpp \
selinux.cpp \
switch_root.cpp \
@ -93,19 +96,16 @@ LOCAL_SANITIZE := signed-integer-overflow
# First stage init is weird: it may start without stdout/stderr, and no /proc.
LOCAL_NOSANITIZE := hwaddress
include $(BUILD_EXECUTABLE)
endif
include $(CLEAR_VARS)
LOCAL_MODULE := init_system
LOCAL_REQUIRED_MODULES := \
init_second_stage \
ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
LOCAL_REQUIRED_MODULES := \
init_first_stage \
init_second_stage \
else
LOCAL_REQUIRED_MODULES := \
init_second_stage \
LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
endif
include $(BUILD_PHONY_PACKAGE)
@ -118,5 +118,3 @@ LOCAL_REQUIRED_MODULES := \
endif
include $(BUILD_PHONY_PACKAGE)

View file

@ -14,6 +14,8 @@
* limitations under the License.
*/
#include "first_stage_init.h"
#include <dirent.h>
#include <fcntl.h>
#include <paths.h>
@ -94,7 +96,7 @@ bool ForceNormalBoot() {
} // namespace
int main(int argc, char** argv) {
int FirstStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
@ -214,7 +216,7 @@ int main(int argc, char** argv) {
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
const char* path = "/system/bin/init";
const char* args[] = {path, nullptr};
const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
@ -226,7 +228,3 @@ int main(int argc, char** argv) {
} // namespace init
} // namespace android
int main(int argc, char** argv) {
return android::init::main(argc, argv);
}

25
init/first_stage_init.h Normal file
View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2018 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
namespace android {
namespace init {
int FirstStageMain(int argc, char** argv);
} // namespace init
} // namespace android

21
init/first_stage_main.cpp Normal file
View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 2018 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.
*/
#include "first_stage_init.h"
int main(int argc, char** argv) {
return android::init::FirstStageMain(argc, argv);
}

View file

@ -59,13 +59,8 @@
#include "security.h"
#include "selinux.h"
#include "sigchld_handler.h"
#include "ueventd.h"
#include "util.h"
#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
#endif
using namespace std::chrono_literals;
using namespace std::string_literals;
@ -79,25 +74,6 @@ using android::base::Trim;
namespace android {
namespace init {
#if __has_feature(address_sanitizer)
// Load asan.options if it exists since these are not yet in the environment.
// Always ensure detect_container_overflow=0 as there are false positives with this check.
// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
extern "C" const char* __asan_default_options() {
return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
}
__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
__sanitizer_report_error_summary(const char* summary) {
LOG(ERROR) << "Main stage (error summary): " << summary;
}
__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
AsanReportCallback(const char* str) {
LOG(ERROR) << "Main stage: " << str;
}
#endif
static int property_triggers_enabled = 0;
static char qemu[32];
@ -622,57 +598,11 @@ static void GlobalSeccomp() {
});
}
static void SetupSelinux(char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
});
// Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
SelinuxInitialize();
// We're in the kernel domain and want to transition to the init domain. File systems that
// store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
// but other file systems do. In particular, this is needed for ramdisks such as the
// recovery image for A/B devices.
if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
}
setenv("SELINUX_INITIALIZED", "true", 1);
const char* path = "/system/bin/init";
const char* args[] = {path, nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
// panic and never return from this function.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
}
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
if (getenv("SELINUX_INITIALIZED") == nullptr) {
SetupSelinux(argv);
}
// We need to set up stdin/stdout/stderr again now that we're running in init's context.
InitKernelLogging(argv, InitAborter);
LOG(INFO) << "init second stage started!";
@ -708,7 +638,6 @@ int main(int argc, char** argv) {
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
unsetenv("SELINUX_INITIALIZED");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");

View file

@ -50,7 +50,7 @@ void DumpState();
void ResetWaitForProp();
int main(int argc, char** argv);
int SecondStageMain(int argc, char** argv);
} // namespace init
} // namespace android

View file

@ -14,8 +14,70 @@
* limitations under the License.
*/
#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"
#include <android-base/logging.h>
#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
#endif
#if __has_feature(address_sanitizer)
// Load asan.options if it exists since these are not yet in the environment.
// Always ensure detect_container_overflow=0 as there are false positives with this check.
// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
extern "C" const char* __asan_default_options() {
return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
}
__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
__sanitizer_report_error_summary(const char* summary) {
LOG(ERROR) << "Init (error summary): " << summary;
}
__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
AsanReportCallback(const char* str) {
LOG(ERROR) << "Init: " << str;
}
#endif
using namespace android::init;
int main(int argc, char** argv) {
android::init::main(argc, argv);
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc < 2) {
return FirstStageMain(argc, argv);
}
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
android::base::InitLogging(argv, &android::base::KernelLogger);
LOG(ERROR) << "Unknown argument passed to init '" << argv[1] << "'";
return 1;
}

View file

@ -18,8 +18,8 @@
// for SELinux operation for init.
// When the system boots, there is no SEPolicy present and init is running in the kernel domain.
// Init loads the SEPolicy from the file system, restores the context of /init based on this
// SEPolicy, and finally exec()'s itself to run in the proper domain.
// Init loads the SEPolicy from the file system, restores the context of /system/bin/init based on
// this SEPolicy, and finally exec()'s itself to run in the proper domain.
// The SEPolicy on Android comes in two variants: monolithic and split.
@ -58,8 +58,10 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <selinux/android.h>
#include "reboot_utils.h"
#include "util.h"
using android::base::ParseInt;
@ -379,8 +381,6 @@ bool LoadPolicy() {
return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
}
} // namespace
void SelinuxInitialize() {
Timer t;
@ -405,6 +405,8 @@ void SelinuxInitialize() {
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}
} // namespace
// The files and directories that were created before initial sepolicy load or
// files on ramdisk need to have their security context restored to the proper
// value. This must happen before /dev is populated by ueventd.
@ -496,6 +498,39 @@ int SelinuxGetVendorAndroidVersion() {
return major_version;
}
// This function initializes SELinux then execs init to run in the init SELinux context.
int SetupSelinux(char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
});
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
// Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
SelinuxInitialize();
// We're in the kernel domain and want to transition to the init domain. File systems that
// store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
// but other file systems do. In particular, this is needed for ramdisks such as the
// recovery image for A/B devices.
if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
}
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
// panic and never return from this function.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
return 1;
}
// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
// its value. selinux_android_restorecon() also needs an sehandle for file context look up. It
// will create and store its own copy, but selinux_android_set_sehandle() can be used to provide

View file

@ -23,7 +23,7 @@
namespace android {
namespace init {
void SelinuxInitialize();
int SetupSelinux(char** argv);
void SelinuxRestoreContext();
void SelinuxSetupKernelLogging();