thehajime / linux

Linux kernel source tree
https://lkl.github.io/
Other
3 stars 1 forks source link

endless loop with respawn with inittab #22

Closed thehajime closed 2 days ago

thehajime commented 1 week ago

- before /bin/sh might be the issue

# /etc/inittab

::sysinit:/etc/init.d/rcS

+::respawn:/bin/sh
-# XXX: '-' makes endless loop with busybox 1.36.1
-#::respawn:-/bin/sh

# Stuff to do when restarting the init process
::restart:/sbin/init

# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
thehajime commented 1 week ago
static void init_exec(const char *command)
{
    /* +8 allows to write VLA sizes below more efficiently: */
    unsigned command_size = strlen(command) + 8;
    /* strlen(command) + strlen("exec ")+1: */
    char buf[command_size];
    /* strlen(command) / 2 + 4: */
    char *cmd[command_size / 2];
    int dash;

(in busybox/init/init.c)

around this area, child after vfork before exec, stack becomes corrupted and command_size becomes huge. during that, it has hard_handler with SIGALRM, which might be relevant (or not) to be puzzled...

thehajime commented 1 week ago

with CONFIG_DEBUG, the stack corruption above disappeared... but after that, rcS finished w/o problems but stacked at spawn /bin/sh in endless manner.

around this area, child after vfork before exec, stack becomes corrupted and command_size becomes huge. during that, it has hard_handler with SIGALRM, which might be relevant (or not) to be puzzled...

this might not be related. even if i stopped SIGALRM by handle SIGALRM nostop print nopass, the corruption happened.

thehajime commented 2 days ago

when hush is invoked from init (via inittab), the argv[0] variable on hush_main is -/bin/sh, which is the variable set in inittab. if argv[0][0] == '-', hush tries to load /etc/profile.

Then, in the profile file, there is id -u command, which also (internally) invokes hush via re_execute_command, with the argv[0][0] == '-', which trigger another /etc/profile load again (recursively).

so, it won't stop until memory failures occur.

this diff (not upstreamed) to busybox fixes this issue.

diff --git a/shell/hush.c b/shell/hush.c
index 6b6ec7c6b..ae027dcae 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -10337,6 +10337,8 @@ int hush_main(int argc, char **argv)
        _exit(0);
    }
    G.argv0_for_re_execing = argv[0];
+   if (G.argv0_for_re_execing[0] == '-')
+       G.argv0_for_re_execing += 1;
 #endif
 #if ENABLE_HUSH_TRAP
 # if ENABLE_HUSH_FUNCTIONS