From 142c943721615020bca80de4c69e6bbf574529aa Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 22 Oct 2018 12:00:02 +0200 Subject: pppd_compat: fix handling of fork() failures When accel-ppp is under stress (for example because of massive disconnections) it may enter a state where no session could be created or destroyed anymore. This happens when at least one of the pppd_compat fork() fail. In this case, the error code path doesn't unlock the sigchld handler, which prevents it from running the completion callbacks of running scripts. If the "fork-limit" option is used, failure to call the completion callback will prevent other scripts from running. This will block setting up and tearing down sessions, as those will wait indefinitely for their pppd_compat scripts to run. Therefore, we have to unlock the sigchld handler when fork() fails. We also need to call fork_queue_wakeup(), because the previous check_fork_limit() call already took one reference in the fork limit. Finally, ev_ses_pre_up() is a bit special because it has to tear the session down if the ip-pre-up script failed. Therefore it also has to call ap_session_terminate() upon fork() failures. Signed-off-by: Guillaume Nault --- accel-pppd/extra/pppd_compat.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'accel-pppd/extra') diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index 7c23eca..6761e5b 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -275,8 +275,12 @@ static void ev_ses_pre_up(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_pre_up, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + ap_session_terminate(ses, TERM_NAS_ERROR, 0); + } } static void ev_ses_started(struct ap_session *ses) @@ -325,8 +329,11 @@ static void ev_ses_started(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_up, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } static void ev_ses_finished(struct ap_session *ses) @@ -385,8 +392,11 @@ static void ev_ses_finished(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_down, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } if (pd->ip_up_hnd.pid) { @@ -474,8 +484,11 @@ static void ev_radius_coa(struct ev_radius_t *ev) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } } -- cgit v1.2.3