From 48a1b6b697f86878d69e919528029a963e22c936 Mon Sep 17 00:00:00 2001
From: James Bottomley <James.Bottomley@HansenPartnership.com>
Date: Mon, 15 Jan 2024 14:38:35 -0500
Subject: [PATCH] Add normal boot re-exec on Signal

If SIGUSR1 is sent, re-exec the init with the "normal" parameter which
forces a normal boot regardless of the state of the
androidboot.force_normal_boot flag.

Change-Id: Ibcfc95a2ce616e9dfd0c1e0529992f9c15f00631
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 init/first_stage_init.cpp |  5 +++--
 init/init.cpp             | 15 +++++++++++++++
 init/main.cpp             |  5 +++++
 init/selinux.cpp          |  4 ++++
 init/switch_root.cpp      |  4 ++--
 init/util.cpp             |  1 +
 init/util.h               |  1 +
 7 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index c7b7b0c13..9ca37f7ec 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -104,7 +104,8 @@ void FreeRamdisk(DIR* dir, dev_t dev) {
 
 bool ForceNormalBoot(const std::string& cmdline, const std::string& bootconfig) {
     return bootconfig.find("androidboot.force_normal_boot = \"1\"") != std::string::npos ||
-           cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
+           cmdline.find("androidboot.force_normal_boot=1") != std::string::npos ||
+      force_normal_boot;
 }
 
 }  // namespace
@@ -261,7 +262,7 @@ int FirstStageMain(int argc, char** argv) {
     // talk to the outside world...
     InitKernelLogging(argv);
 
-    if (!errors.empty()) {
+    if (false) {
         for (const auto& [error_string, error_errno] : errors) {
             LOG(ERROR) << error_string << " " << strerror(error_errno);
         }
diff --git a/init/init.cpp b/init/init.cpp
index 942feb939..8db3fa5bd 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -593,6 +593,20 @@ static void HandleSignalFd() {
         case SIGTERM:
             HandleSigtermSignal(siginfo);
             break;
+        case SIGUSR1: {
+            const char *path = "/system/bin/init";
+            const char* args[] = {path, "normal", nullptr};
+
+            LOG(INFO) << "SIGUSR1 received";
+
+	    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
+	      LOG(FATAL) << "restorecon failed of /system/bin/init failed";
+	    }
+
+            execv(path, const_cast<char **>(args));
+	    LOG(ERROR) << "Exec returned";
+            break;
+        }
         default:
             PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
             break;
@@ -622,6 +636,7 @@ static void InstallSignalFdHandler(Epoll* epoll) {
     sigset_t mask;
     sigemptyset(&mask);
     sigaddset(&mask, SIGCHLD);
+    sigaddset(&mask, SIGUSR1);
 
     if (!IsRebootCapable()) {
         // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
diff --git a/init/main.cpp b/init/main.cpp
index 23f5530fe..9a1f6a236 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -20,6 +20,7 @@
 #include "selinux.h"
 #include "subcontext.h"
 #include "ueventd.h"
+#include "util.h"
 
 #include <android-base/logging.h>
 
@@ -66,6 +67,10 @@ int main(int argc, char** argv) {
             return SubcontextMain(argc, argv, &function_map);
         }
 
+	if (!strcmp(argv[1], "normal")) {
+	  force_normal_boot = true;
+	}
+
         if (!strcmp(argv[1], "selinux_setup")) {
             return SetupSelinux(argv);
         }
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 29c0ff3ba..2d768e0cc 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -739,6 +739,9 @@ int SetupSelinux(char** argv) {
 
     MountMissingSystemPartitions();
 
+    // we've already done selinux setup, so skip to second stage
+    if (!force_normal_boot) {
+
     SelinuxSetupKernelLogging();
 
     LOG(INFO) << "Opening SELinux policy";
@@ -764,6 +767,7 @@ int SetupSelinux(char** argv) {
     }
 
     SelinuxSetEnforcement();
+    } // force_normal_boot
 
     // 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,
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index 575b67f38..176d9521e 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -77,7 +77,7 @@ void SwitchRoot(const std::string& new_root) {
     for (const auto& mount_path : mounts) {
         auto new_mount_path = new_root + mount_path;
         mkdir(new_mount_path.c_str(), 0755);
-        if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
+        if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
             PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
         }
     }
@@ -86,7 +86,7 @@ void SwitchRoot(const std::string& new_root) {
         PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
     }
 
-    if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
+    if (mount(new_root.c_str(), "/", nullptr, MS_BIND, nullptr) != 0) {
         PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
     }
 
diff --git a/init/util.cpp b/init/util.cpp
index 9f7bfdb5b..e25345490 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -62,6 +62,7 @@ namespace init {
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
 
 void (*trigger_shutdown)(const std::string& command) = nullptr;
+bool force_normal_boot = false;
 
 // DecodeUid() - decodes and returns the given string, which can be either the
 // numeric or name representation, into the integer uid or gid.
diff --git a/init/util.h b/init/util.h
index daba85247..e44be86cc 100644
--- a/init/util.h
+++ b/init/util.h
@@ -43,6 +43,7 @@ enum mount_mode {
 static const char kColdBootDoneProp[] = "ro.cold_boot_done";
 
 extern void (*trigger_shutdown)(const std::string& command);
+extern bool force_normal_boot;
 
 Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
                          gid_t gid, const std::string& socketcon);
-- 
2.43.0

