From ee880b37c1522346a6a641bb5d532e94511df86f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 30 Oct 2019 17:41:15 +0100 Subject: [PATCH] sd-event: refuse sd_event_add_child() if SIGCHLD is not blocked We already refuse sd_event_add_signal() if the specified signal is not blocked, let's do this also for sd_event_add_child(), since we might need signalfd() to implement this, and this means the signal needs to be blocked. --- src/libsystemd/sd-event/sd-event.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index bb3c542b7c..8d4a20e420 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -1239,6 +1239,20 @@ _public_ int sd_event_add_child( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (e->n_enabled_child_sources == 0) { + /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, + * for compatibility with pre-pidfd and because we don't want the reap the child processes + * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to + * take effect. + * + * (As an optimization we only do this check on the first child event source created.) */ + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + r = hashmap_ensure_allocated(&e->child_sources, NULL); if (r < 0) return r; @@ -1326,6 +1340,14 @@ _public_ int sd_event_add_child_pidfd( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (e->n_enabled_child_sources == 0) { + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + r = hashmap_ensure_allocated(&e->child_sources, NULL); if (r < 0) return r;