From 41f677ec5daccaeae616a0bbf508d2a2d54bdac7 Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Sat, 31 May 2025 09:56:09 +0800 Subject: crond: reap orphaned grandchildren to prevent zombie buildup If a cron job launches a background task, e.g. `sh -c "sleep 5 &"`, the shell exits immediately and the `sleep` process is re-parented to PID 1. When BusyBox `crond` itself happens to be PID 1 (common in a minimal container), those orphans become direct children of `crond`. Because `crond` only calls waitpid() for the PIDs it explicitly tracks, these processes remain forever in Z state and the container slowly fills with zombies. Add a small `while (waitpid(-1, NULL, WNOHANG) > 0)` sweep at the end of check_completions() so any stray children are reaped. When `crond` is not PID 1 the loop returns -ECHILD immediately, so behaviour and overhead on a normal system are unchanged. Size impact: +12 bytes on x86-64 (gcc 13.3.0 -Os, static) Signed-off-by: Valentin Lab Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'miscutils') diff --git a/miscutils/crond.c b/miscutils/crond.c index 96131cae4..b29745576 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -1001,6 +1001,10 @@ static int check_completions(void) /* else: r == 0: "process is still running" */ file->cf_has_running = 1; } + + /* Reap any other children we don't actively track */ + while (waitpid(-1, NULL, WNOHANG) > 0); + //FIXME: if !file->cf_has_running && file->deleted: delete it! //otherwise deleted entries will stay forever, right? num_still_running += file->cf_has_running; -- cgit v1.2.3-55-g6feb From a98b95b715359a8b002d1cb8e1f998a4afa2c73e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Jul 2025 20:02:23 +0200 Subject: *: use safe_waitpid() or wait_any_nohang() where approppriate function old new delta crond_main 1227 1237 +10 init_main 804 794 -10 wait_one 263 252 -11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 10/-21) Total: -11 bytes Signed-off-by: Denys Vlasenko --- e2fsprogs/fsck.c | 4 +--- init/init.c | 2 +- miscutils/crond.c | 10 +++++++--- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'miscutils') diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c index fd4ea737c..f7e93497d 100644 --- a/e2fsprogs/fsck.c +++ b/e2fsprogs/fsck.c @@ -423,13 +423,11 @@ static int wait_one(int flags) /* if (G.noexecute) { already returned -1; } */ while (1) { - pid = waitpid(-1, &status, flags); + pid = safe_waitpid(-1, &status, flags); kill_all_if_got_signal(); if (pid == 0) /* flags == WNOHANG and no children exited */ return -1; if (pid < 0) { - if (errno == EINTR) - continue; if (errno == ECHILD) { /* paranoia */ bb_simple_error_msg("wait: no more children"); return -1; diff --git a/init/init.c b/init/init.c index 797e0a0eb..294be9952 100644 --- a/init/init.c +++ b/init/init.c @@ -1201,7 +1201,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) int status; struct init_action *a; - wpid = waitpid(-1, &status, WNOHANG); + wpid = wait_any_nohang(&status); if (wpid <= 0) break; diff --git a/miscutils/crond.c b/miscutils/crond.c index b29745576..6a384fdfb 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -989,7 +989,7 @@ static int check_completions(void) if (line->cl_pid <= 0) continue; - r = waitpid(line->cl_pid, NULL, WNOHANG); + r = safe_waitpid(line->cl_pid, NULL, WNOHANG); if (r < 0 || r == line->cl_pid) { process_finished_job(file->cf_username, line); if (line->cl_pid == 0) { @@ -1002,8 +1002,12 @@ static int check_completions(void) file->cf_has_running = 1; } - /* Reap any other children we don't actively track */ - while (waitpid(-1, NULL, WNOHANG) > 0); + /* Reap any other children we don't actively track. + * Reportedly, some people run crond as init process! + * Thus, we need to reap orphans, like init does. + */ + while (wait_any_nohang(NULL) > 0) + continue; //FIXME: if !file->cf_has_running && file->deleted: delete it! //otherwise deleted entries will stay forever, right? -- cgit v1.2.3-55-g6feb