The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=1a669b66ddb4748c24116e32dcb51eabaf4859ed
commit 1a669b66ddb4748c24116e32dcb51eabaf4859ed Author: Baptiste Daroussin <[email protected]> AuthorDate: 2026-09-02 08:51:42 +0000 Commit: Baptiste Daroussin <[email protected]> CommitDate: 2026-09-02 15:00:58 +0000 syslogd: reap pipe children on config reload On SIGHUP reload, closelogfiles() frees each F_PIPE filed even when its pipe process is still running. close_filed() sets f_type to F_UNUSED before the check, so the condition f_type != F_PIPE is always true and the filed is freed while its process descriptor is still on the dead queue and registered in the kqueue. When the child later exits, the NOTE_EXIT handler dereferences the freed filed (use-after-free) and never closes the process descriptor, leaving the pipe child as a persistent zombie. Capture whether the filed is a pipe with an active process descriptor before calling close_filed(), and defer the free in that case so the NOTE_EXIT handler can reap the child and free the filed. Reviewed by: markj Fixes: 95381c0139d6 (syslogd: Use process descriptors) Differential Revision: https://reviews.freebsd.org/D59319 --- usr.sbin/syslogd/syslogd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index e3d144a532b5..f12013c1f316 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -2549,6 +2549,7 @@ void closelogfiles(void) { struct filed *f; + bool defer_free; while (!STAILQ_EMPTY(&fhead)) { f = STAILQ_FIRST(&fhead); @@ -2558,6 +2559,13 @@ closelogfiles(void) if (f->f_prevcount) fprintlog_successive(f, 0); + /* + * If a piped process is running, then defer the filed + * cleanup until it exits. close_filed() below sets + * f_type to F_UNUSED, so capture this before calling it. + */ + defer_free = (f->f_type == F_PIPE && f->f_procdesc != -1); + switch (f->f_type) { case F_FILE: case F_FORW: @@ -2585,11 +2593,7 @@ closelogfiles(void) free(f->f_prop_filter); } - /* - * If a piped process is running, then defer the filed - * cleanup until it exits. - */ - if (f->f_type != F_PIPE || f->f_procdesc == -1) + if (!defer_free) free(f); } }
