Hi all, We put together a test to try out the various suggestions on double-forking processes to see if polling for a zombie process being reaped by INIT would help provide a method to synchronize the ready state of the signal handlers for reboot and poweroff paths in Busybox INIT during early IPL.
The usermode helper that kicks Busybox /sbin/poweroff (started by PID=2) is very early, even before Busybox INIT is do_execve'd from kernel_init. We found that any process zombies in this early stage of kernel_init get flushed when the do_execve is done for Busybox /sbin/init. Specifically we traced the program flow to proc_flush_task_mnt from linux/fs/proc/base.c. We tested out the following patch and the race is fixed using the abstract socket. **************************************************************************** >From 1a7ac3aba3e94bd04de48e9619647cca853dca06 Mon Sep 17 00:00:00 2001 From: Deb McLemore <[email protected]> Date: Wed, 25 Oct 2017 08:06:20 -0500 Subject: [PATCH] init: Add handshake to poweroff/reboot for signal handler setup Add an abstract socket to synchronize the readiness of init to receive the SIGUSR2 to catch poweroff/reboot during an IPL phase (e.g. soft power off via BMC). Signed-off-by: Deb McLemore <[email protected]> --- init/halt.c | 37 +++++++++++++++++++++++++++++++++++++ init/init.c | 23 +++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/init/halt.c b/init/halt.c index c6c857f..510c4d2 100644 --- a/init/halt.c +++ b/init/halt.c @@ -83,6 +83,10 @@ #include "libbb.h" #include "reboot.h" +#ifdef __linux__ +#include <sys/un.h> +#endif + #if ENABLE_FEATURE_WTMP #include <sys/utsname.h> @@ -112,6 +116,12 @@ static void write_wtmp(void) int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int halt_main(int argc UNUSED_PARAM, char **argv) { + +#ifdef __linux__ + struct sockaddr_un bb_addr2; + int fdBB2 = 0; + int fdrc = 0; +#endif static const int magic[] = { RB_HALT_SYSTEM, RB_POWER_OFF, @@ -170,6 +180,33 @@ int halt_main(int argc UNUSED_PARAM, char **argv) /* talk to init */ if (!ENABLE_FEATURE_CALL_TELINIT) { /* bbox init assumed */ + + /* Use socket connect to INIT to assure that + * signal handlers are ready + */ + #ifdef __linux__ + memset(&bb_addr2, + 0, + sizeof(struct sockaddr_un)); + bb_addr2.sun_family = AF_UNIX; + strcpy(bb_addr2.sun_path, + "\0bb_signals"); + while (1) { + fdBB2 = socket(AF_UNIX, + SOCK_CLOEXEC | SOCK_DGRAM, 0); + if (fdBB2 != -1) + break; + sleep(1); + } + while (1) { + fdrc = connect(fdBB2, + (struct sockaddr *)&bb_addr2, + sizeof(struct sockaddr_un)); + if (fdrc == 0) + break; + sleep(1); + } + #endif rc = kill(1, signals[which]); } else { /* SysV style init assumed */ diff --git a/init/init.c b/init/init.c index 6f3374e..3308a6e 100644 --- a/init/init.c +++ b/init/init.c @@ -133,6 +133,7 @@ #ifdef __linux__ # include <linux/vt.h> # include <sys/sysinfo.h> +# include <sys/un.h> #endif #include "reboot.h" /* reboot() constants */ @@ -1046,6 +1047,12 @@ static void sleep_much(void) int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { + +#ifdef __linux__ + struct sockaddr_un bb_addr; + int fdBB = 0; +#endif + if (argv[1] && strcmp(argv[1], "-q") == 0) { return kill(1, SIGHUP); } @@ -1191,6 +1198,22 @@ int init_main(int argc UNUSED_PARAM, char **argv) sigprocmask_allsigs(SIG_UNBLOCK); } +#ifdef __linux__ + memset(&bb_addr, 0, sizeof(struct sockaddr_un)); + bb_addr.sun_family = AF_UNIX; + strcpy(bb_addr.sun_path, "\0bb_signals"); + /* Create an abstract socket to use for synchronizing poweroff and + * reboot which could be kicked at IPL before the INIT process + * completes signal setup to listen for the signals + * Ignore failures and keep on, this just helps + * close the exposed window when nothing will get signaled + * The abstract socket needs to stay persistent, so no cleanup + */ + fdBB = socket(AF_UNIX, SOCK_CLOEXEC | SOCK_DGRAM, 0); + if (fdBB != -1) + bind(fdBB, (struct sockaddr *)&bb_addr, sizeof(bb_addr)); +#endif + /* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); -- 2.7.4 _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
