[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: Re: Race in reboot/poweroff path at init?
From: Deb McLemore <debmc () linux ! vnet ! ibm ! com>
Date: 2017-11-24 3:47:33
Message-ID: b5f5e001-0af4-4289-ae7d-3bf7230980e1 () linux ! vnet ! ibm ! com
[Download RAW message or body]
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 <debmc@linux.vnet.ibm.com>
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 <debmc@linux.vnet.ibm.com>
---
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
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic