From 5c9eb30727331780e01cd34293801efd38aa787d Mon Sep 17 00:00:00 2001
From: huyubiao <h13958451065@163.com>
Date: Fri, 16 Jun 2023 15:32:28 +0800
Subject: [PATCH] fix: init uses SIGABRT to reexec sysmaster, increase signal
 permissions

---
 core/bin/main.rs                 | 46 ++++++++++++++++----------------
 core/bin/manager/mod.rs          |  9 ++++++-
 exts/init/Cargo.toml             |  1 -
 exts/init/src/runtime/mod.rs     | 33 +++++++++--------------
 exts/init/src/runtime/signals.rs | 19 +++++++------
 libs/constants/src/lib.rs        |  2 --
 7 files changed, 60 insertions(+), 62 deletions(-)

diff --git a/core/bin/main.rs b/core/bin/main.rs
index 0239ce9..7f163c7 100644
--- a/core/bin/main.rs
+++ b/core/bin/main.rs
@@ -39,7 +39,7 @@ use crate::mount::setup;
 use basic::logger::{self};
 use basic::process_util;
 use clap::Parser;
-use libc::{c_int, getppid, prctl, PR_SET_CHILD_SUBREAPER};
+use libc::{c_int, getpid, getppid, prctl, PR_SET_CHILD_SUBREAPER};
 use log::{self};
 use manager::signals::EVENT_SIGNALS;
 use nix::sys::resource::{self, Resource};
@@ -52,7 +52,6 @@ use std::rc::Rc;
 use sysmaster::error::*;
 use sysmaster::rel;
 
-use constants::SIG_MANAGER_REEXEC_OFFSET;
 use constants::SIG_SWITCH_ROOT_OFFSET;
 
 /// parse program arguments
@@ -106,21 +105,17 @@ fn main() -> Result<()> {
     setup::mount_setup()?;
 
     rel::reli_dir_prepare()?;
-    let switch = rel::reli_debug_get_switch();
-    log::info!("sysmaster initialize with switch: {}.", switch);
+    let self_recovery_enable = rel::reli_debug_get_switch();
+    log::info!("sysmaster self_recovery_enable: {}.", self_recovery_enable);
 
-    initialize_runtime(switch)?;
+    initialize_runtime(self_recovery_enable)?;
 
     let manager = Manager::new(Mode::System, Action::Run, manager_config);
 
-    // enable clear, mutex with install_crash_handler
-    if !switch {
-        if !args.deserialize {
-            manager.debug_clear_restore();
-            log::info!("debug: clear data restored.");
-        }
-        // if switch is false unregister init's reexec signal.
-        register_reexec_signal(false);
+    // enable clear
+    if !self_recovery_enable && !args.deserialize {
+        manager.debug_clear_restore();
+        log::info!("debug: clear data restored.");
     }
 
     manager.setup_cgroup()?;
@@ -144,10 +139,13 @@ fn main() -> Result<()> {
     Ok(())
 }
 
-fn initialize_runtime(switch: bool) -> Result<()> {
-    if switch {
+fn initialize_runtime(self_recovery_enable: bool) -> Result<()> {
+    if self_recovery_enable {
         install_crash_handler();
         log::info!("install crash handler.");
+    } else {
+        // if self_recovery_enable is false unregister init's reexec signal.
+        register_reexec_signal(false);
     }
 
     #[cfg(feature = "linux")]
@@ -222,7 +220,7 @@ fn install_crash_handler() {
         Signal::SIGABRT,
         Signal::SIGSYS,
     ];
-    let handler = SigHandler::Handler(crash);
+    let handler = SigHandler::SigAction(crash);
     let flags = SaFlags::SA_NODEFER;
     let action = SigAction::new(handler, flags, SigSet::empty());
     for &signal in signals.iter() {
@@ -232,11 +230,14 @@ fn install_crash_handler() {
     }
 }
 
-extern "C" fn crash(signo: c_int) {
-    let _signal = Signal::try_from(signo).unwrap(); // debug
-
-    let args: Vec<String> = env::args().collect();
-    do_reexecute(&args, false);
+extern "C" fn crash(signo: c_int, siginfo: *mut libc::siginfo_t, _con: *mut libc::c_void) {
+    let signal = Signal::try_from(signo).unwrap(); // debug
+    if (signal == Signal::SIGABRT && unsafe { (*siginfo).si_pid() == getppid() })
+        || unsafe { (*siginfo).si_pid() == getpid() }
+    {
+        let args: Vec<String> = env::args().collect();
+        do_reexecute(&args, false);
+    }
 }
 
 fn execarg_build_default() -> (String, Vec<String>) {
@@ -265,8 +266,7 @@ extern "C" fn crash_none(_signo: c_int, _siginfo: *mut libc::siginfo_t, _con: *m
 }
 
 fn register_reexec_signal(enable: bool) {
-    let manager_signal: signal::Signal =
-        unsafe { std::mem::transmute(libc::SIGRTMIN() + SIG_MANAGER_REEXEC_OFFSET) };
+    let manager_signal: Signal = Signal::SIGABRT;
     let handler = match enable {
         true => SigHandler::SigAction(crash_reexec),
         false => SigHandler::SigAction(crash_none),
diff --git a/core/bin/manager/mod.rs b/core/bin/manager/mod.rs
index e972cc7..7bd16e0 100644
--- a/core/bin/manager/mod.rs
+++ b/core/bin/manager/mod.rs
@@ -59,6 +59,12 @@ impl SignalMgr {
         SignalMgr { um: Rc::clone(&um) }
     }
     fn reexec(&self) -> Result<i32> {
+        self.um.set_state(State::ReExecute);
+        Ok(1)
+    }
+
+    fn reload(&self) -> Result<i32> {
+        self.um.set_state(State::ReLoad);
         Ok(1)
     }
 }
@@ -70,7 +76,8 @@ impl SignalDispatcher for SignalMgr {
             return Ok(1);
         }
         match signal.ssi_signo as libc::c_int {
-            libc::SIGHUP | libc::SIGTERM => self.reexec(),
+            libc::SIGHUP => self.reload(),
+            libc::SIGTERM => self.reexec(),
             libc::SIGCHLD => Ok(self.um.child_sigchld_enable(true)),
             /* Kernel will send SIGINT to PID1 when users press ctrl-alt-del,
              * init should forward SIGINT to sysmaster. */
diff --git a/exts/init/Cargo.toml b/exts/init/Cargo.toml
index e3c0198..e351b61 100644
--- a/exts/init/Cargo.toml
+++ b/exts/init/Cargo.toml
@@ -9,4 +9,3 @@ edition = "2021"
 constants = { version = "0.1.0", path = "../../libs/constants" }
 libc = "0.2.*"
 nix = "0.24"
-signal-hook-registry = "1.4.0"
diff --git a/exts/init/src/runtime/mod.rs b/exts/init/src/runtime/mod.rs
index e37ff01..d11d8f2 100644
--- a/exts/init/src/runtime/mod.rs
+++ b/exts/init/src/runtime/mod.rs
@@ -33,7 +33,6 @@ use std::rc::Rc;
 
 use constants::SIG_SWITCH_ROOT_OFFSET;
 const INVALID_PID: i32 = -1;
-const MANAGER_SIG_OFFSET: i32 = 7;
 const SYSMASTER_PATH: &str = "/usr/lib/sysmaster/sysmaster";
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
@@ -152,12 +151,7 @@ impl RunTime {
 
         self.comm.finish();
 
-        unsafe {
-            libc::kill(
-                self.sysmaster_pid.into(),
-                libc::SIGRTMIN() + MANAGER_SIG_OFFSET,
-            )
-        };
+        unsafe { libc::kill(self.sysmaster_pid.into(), libc::SIGABRT) };
     }
 
     fn reexec_comm_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
@@ -187,11 +181,10 @@ impl RunTime {
 
     fn reexec_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
         if let Some(siginfo) = self.signals.read(event)? {
-            let signo = siginfo.ssi_signo as i32;
-            match signo {
-                _x if self.signals.is_zombie(signo) => self.do_recycle(),
-                _x if self.signals.is_restart(signo) => self.do_reexec(),
-                _x if self.signals.is_unrecover(signo) => self.change_to_unrecover(),
+            match siginfo {
+                _x if self.signals.is_zombie(siginfo) => self.do_recycle(),
+                _x if self.signals.is_restart(siginfo) => self.do_reexec(),
+                _x if self.signals.is_unrecover(siginfo) => self.change_to_unrecover(),
                 _ => {}
             }
         }
@@ -200,11 +193,10 @@ impl RunTime {
 
     fn run_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
         if let Some(siginfo) = self.signals.read(event)? {
-            let signo = siginfo.ssi_signo as i32;
-            match signo {
-                _x if self.signals.is_zombie(signo) => self.do_recycle(),
-                _x if self.signals.is_restart(signo) => self.do_reexec(),
-                _x if self.signals.is_switch_root(signo) => self.send_switch_root_signal(),
+            match siginfo {
+                _x if self.signals.is_zombie(siginfo) => self.do_recycle(),
+                _x if self.signals.is_restart(siginfo) => self.do_reexec(),
+                _x if self.signals.is_switch_root(siginfo) => self.send_switch_root_signal(),
                 _ => {}
             }
         }
@@ -213,15 +205,14 @@ impl RunTime {
 
     fn unrecover_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
         if let Some(siginfo) = self.signals.read(event)? {
-            let signo = siginfo.ssi_signo as i32;
-            match signo {
-                _x if self.signals.is_zombie(signo) => {
+            match siginfo {
+                _x if self.signals.is_zombie(siginfo) => {
                     self.signals.recycle_zombie();
                     if self.is_sysmaster(siginfo.ssi_pid as i32) && self.switching {
                         self.reexec_self()
                     }
                 }
-                _x if self.signals.is_restart(signo) => self.do_recreate(),
+                _x if self.signals.is_restart(siginfo) => self.do_recreate(),
                 _ => {}
             }
         }
diff --git a/exts/init/src/runtime/signals.rs b/exts/init/src/runtime/signals.rs
index eee088c..1c3059c 100644
--- a/exts/init/src/runtime/signals.rs
+++ b/exts/init/src/runtime/signals.rs
@@ -81,20 +81,23 @@ impl Signals {
         }
     }
 
-    pub fn is_zombie(&self, signo: i32) -> bool {
-        self.zombie_signal == signo
+    pub fn is_zombie(&self, siginfo: libc::signalfd_siginfo) -> bool {
+        self.zombie_signal as u32 == siginfo.ssi_signo
     }
 
-    pub fn is_restart(&self, signo: i32) -> bool {
-        self.restart_signal == signo
+    pub fn is_restart(&self, siginfo: libc::signalfd_siginfo) -> bool {
+        self.restart_signal as u32 == siginfo.ssi_signo
     }
 
-    pub fn is_unrecover(&self, signo: i32) -> bool {
-        self.unrecover_signal == signo
+    pub fn is_unrecover(&self, siginfo: libc::signalfd_siginfo) -> bool {
+        if 0 == siginfo.ssi_uid {
+            return self.unrecover_signal as u32 == siginfo.ssi_signo;
+        }
+        false
     }
 
-    pub fn is_switch_root(&self, signo: i32) -> bool {
-        self.switch_root_signal == signo
+    pub fn is_switch_root(&self, siginfo: libc::signalfd_siginfo) -> bool {
+        self.switch_root_signal as u32 == siginfo.ssi_signo
     }
 
     pub fn create_signals_epoll(&mut self) -> Result<(), Errno> {
diff --git a/libs/constants/src/lib.rs b/libs/constants/src/lib.rs
index 7c918aa..b1db27c 100644
--- a/libs/constants/src/lib.rs
+++ b/libs/constants/src/lib.rs
@@ -12,8 +12,6 @@
 
 //! Common used constants by init, sysmaster and other extensions.
 
-/// Signal used to reexecute sysmaster, SIGRTMIN+7
-pub const SIG_MANAGER_REEXEC_OFFSET: i32 = 7;
 /// Signal used run unrecover, SIGRTMIN+8
 pub const SIG_RUN_UNRECOVER_OFFSET: i32 = 8;
 /// Signal used to restart the manager, SIGRTMIN+9
-- 
2.33.0

