[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