Merge "init: clean up the 1st/2nd stage init split"
This commit is contained in:
commit
3ecaf2e7f5
10 changed files with 167 additions and 96 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
25
init/first_stage_init.h
Normal 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
21
init/first_stage_main.cpp
Normal 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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ void DumpState();
|
|||
|
||||
void ResetWaitForProp();
|
||||
|
||||
int main(int argc, char** argv);
|
||||
int SecondStageMain(int argc, char** argv);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
void SelinuxInitialize();
|
||||
int SetupSelinux(char** argv);
|
||||
void SelinuxRestoreContext();
|
||||
|
||||
void SelinuxSetupKernelLogging();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue