From 9b6286055a6359722ea6374567b0d4057c38d755 Mon Sep 17 00:00:00 2001 From: kevans Date: Wed, 1 Jan 2020 04:22:04 +0000 Subject: [PATCH] inetd: track all child pids, regardless of maxchild spec Currently, child pids are only tracked if maxchildren is specified. As a consequence, without a maxchild limit we do not get a notice in syslog on children aborting abnormally. This turns out to be a great debugging aide at times. Children are now tracked in a LIST; the management interface is decidedly less painful when there's no upper bound on the number of entries we may have at the cost of one small allocation per connection. PR: 70335 --- usr.sbin/inetd/inetd.c | 62 +++++++++++++++++++++++------------------- usr.sbin/inetd/inetd.h | 7 ++++- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c index cb3fad815d23..fb52ed9faed5 100644 --- a/usr.sbin/inetd/inetd.c +++ b/usr.sbin/inetd/inetd.c @@ -922,8 +922,8 @@ flag_signal(int signo) static void addchild(struct servtab *sep, pid_t pid) { - if (sep->se_maxchild <= 0) - return; + struct stabchild *sc; + #ifdef SANITY_CHECK if (SERVTAB_EXCEEDS_LIMIT(sep)) { syslog(LOG_ERR, "%s: %d >= %d", @@ -931,7 +931,15 @@ addchild(struct servtab *sep, pid_t pid) exit(EX_SOFTWARE); } #endif - sep->se_pids[sep->se_numchild++] = pid; + sc = malloc(sizeof(*sc)); + if (sc == NULL) { + syslog(LOG_ERR, "malloc: %m"); + exit(EX_OSERR); + } + memset(sc, 0, sizeof(*sc)); + sc->sc_pid = pid; + LIST_INSERT_HEAD(&sep->se_children, sc, sc_link); + ++sep->se_numchild; if (SERVTAB_AT_LIMIT(sep)) disable(sep); } @@ -939,8 +947,9 @@ addchild(struct servtab *sep, pid_t pid) static void reapchild(void) { - int k, status; + int status; pid_t pid; + struct stabchild *sc; struct servtab *sep; for (;;) { @@ -953,14 +962,17 @@ reapchild(void) WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); for (sep = servtab; sep; sep = sep->se_next) { - for (k = 0; k < sep->se_numchild; k++) - if (sep->se_pids[k] == pid) + LIST_FOREACH(sc, &sep->se_children, sc_link) { + if (sc->sc_pid == pid) break; - if (k == sep->se_numchild) + } + if (sc == NULL) continue; if (SERVTAB_AT_LIMIT(sep)) enable(sep); - sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; + LIST_REMOVE(sc, sc_link); + free(sc); + --sep->se_numchild; if (WIFSIGNALED(status) || WEXITSTATUS(status)) syslog(LOG_WARNING, "%s[%d]: exited, %s %u", @@ -1032,18 +1044,14 @@ config(void) sep->se_nomapped = new->se_nomapped; sep->se_reset = 1; } - /* copy over outstanding child pids */ - if (sep->se_maxchild > 0 && new->se_maxchild > 0) { - new->se_numchild = sep->se_numchild; - if (new->se_numchild > new->se_maxchild) - new->se_numchild = new->se_maxchild; - memcpy(new->se_pids, sep->se_pids, - new->se_numchild * sizeof(*new->se_pids)); - } - SWAP(pid_t *, sep->se_pids, new->se_pids); - sep->se_maxchild = new->se_maxchild; - sep->se_numchild = new->se_numchild; + + /* + * The children tracked remain; we want numchild to + * still reflect how many jobs are running so we don't + * throw off our accounting. + */ sep->se_maxcpm = new->se_maxcpm; + sep->se_maxchild = new->se_maxchild; resize_conn(sep, new->se_maxperip); sep->se_maxperip = new->se_maxperip; sep->se_bi = new->se_bi; @@ -1949,13 +1957,7 @@ getconfigent(void) else sep->se_maxchild = 1; } - if (sep->se_maxchild > 0) { - sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); - if (sep->se_pids == NULL) { - syslog(LOG_ERR, "malloc: %m"); - exit(EX_OSERR); - } - } + LIST_INIT(&sep->se_children); argc = 0; for (arg = skip(&cp); cp; arg = skip(&cp)) if (argc < MAXARGV) { @@ -1980,6 +1982,7 @@ getconfigent(void) static void freeconfig(struct servtab *cp) { + struct stabchild *sc; int i; if (cp->se_service) @@ -1996,8 +1999,11 @@ freeconfig(struct servtab *cp) #endif if (cp->se_server) free(cp->se_server); - if (cp->se_pids) - free(cp->se_pids); + while (!LIST_EMPTY(&cp->se_children)) { + sc = LIST_FIRST(&cp->se_children); + LIST_REMOVE(sc, sc_link); + free(sc); + } for (i = 0; i < MAXARGV; i++) if (cp->se_argv[i]) free(cp->se_argv[i]); diff --git a/usr.sbin/inetd/inetd.h b/usr.sbin/inetd/inetd.h index 412dbdcd132e..a7dc89ad7015 100644 --- a/usr.sbin/inetd/inetd.h +++ b/usr.sbin/inetd/inetd.h @@ -66,6 +66,11 @@ struct conninfo { #define PERIPSIZE 256 +struct stabchild { + LIST_ENTRY(stabchild) sc_link; + pid_t sc_pid; +}; + struct servtab { char *se_service; /* name of service */ int se_socktype; /* type of socket to use */ @@ -74,7 +79,6 @@ struct servtab { int se_maxchild; /* max number of children */ int se_maxcpm; /* max connects per IP per minute */ int se_numchild; /* current number of children */ - pid_t *se_pids; /* array of child pids */ char *se_user; /* user name to run as */ char *se_group; /* group name to run as */ #ifdef LOGIN_CAP @@ -119,6 +123,7 @@ struct servtab { } se_flags; int se_maxperip; /* max number of children per src */ LIST_HEAD(, conninfo) se_conn[PERIPSIZE]; + LIST_HEAD(, stabchild) se_children; }; #define se_nomapped se_flags.se_nomapped