git: 95381c0139d6 - main - syslogd: Use process descriptors
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 28 Sep 2023 15:52:33 UTC
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=95381c0139d639c78c922956621cae152471a09b commit 95381c0139d639c78c922956621cae152471a09b Author: Jake Freeland <jfree@FreeBSD.org> AuthorDate: 2023-09-01 02:50:14 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2023-09-28 15:51:53 +0000 syslogd: Use process descriptors Prepare for program Capsicumization by storing process descriptors instead of pids. Signal delivery is not permitted in capability mode, so we can use pdkill(2) to terminate child processes. Reviewed by: markj MFC after: 3 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D41369 --- usr.sbin/syslogd/syslogd.c | 109 ++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 9498b900ed9b..fff45372fda8 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -107,6 +107,7 @@ static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; #include <sys/event.h> #include <sys/ioctl.h> #include <sys/mman.h> +#include <sys/procdesc.h> #include <sys/queue.h> #include <sys/resource.h> #include <sys/socket.h> @@ -298,7 +299,7 @@ struct filed { } f_forw; /* F_FORW */ struct { char f_pname[MAXPATHLEN]; - pid_t f_pid; + int f_procdesc; } f_pipe; /* F_PIPE */ } f_un; #define fu_uname f_un.f_uname @@ -306,7 +307,7 @@ struct filed { #define fu_forw_hname f_un.f_forw.f_hname #define fu_forw_addr f_un.f_forw.f_addr #define fu_pipe_pname f_un.f_pipe.f_pname -#define fu_pipe_pid f_un.f_pipe.f_pid +#define fu_pipe_pd f_un.f_pipe.f_procdesc /* Book-keeping. */ char f_prevline[MAXSVLINE]; /* last message logged */ @@ -327,7 +328,7 @@ static struct filed consfile; /* Console */ * Queue of about-to-be dead processes we should watch out for. */ struct deadq_entry { - pid_t dq_pid; + int dq_procdesc; int dq_timeout; TAILQ_ENTRY(deadq_entry) dq_entries; }; @@ -438,9 +439,9 @@ static void addpeer(const char *, const char *, mode_t); static void addsock(const char *, const char *, mode_t); static void cfline(const char *, const char *, const char *, const char *); static const char *cvthname(struct sockaddr *); -static void deadq_enter(pid_t, const char *); -static int deadq_remove(struct deadq_entry *); -static int deadq_removebypid(pid_t); +static void deadq_enter(int); +static void deadq_remove(struct deadq_entry *); +static bool deadq_removebypid(pid_t); static int decode(const char *, const CODE *); static void die(int) __dead2; static void dofsync(void); @@ -495,7 +496,10 @@ close_filed(struct filed *f) f->f_type = F_UNUSED; break; case F_PIPE: - f->fu_pipe_pid = 0; + if (f->fu_pipe_pd >= 0) { + deadq_enter(f->fu_pipe_pd); + f->fu_pipe_pd = -1; + } break; default: break; @@ -1944,20 +1948,16 @@ fprintlog_write(struct filed *f, struct iovlist *il, int flags) case F_PIPE: dprintf(" %s\n", f->fu_pipe_pname); iovlist_append(il, "\n"); - if (f->fu_pipe_pid == 0) { + if (f->fu_pipe_pd == -1) { if ((f->f_file = p_open(f->fu_pipe_pname, - &f->fu_pipe_pid)) < 0) { + &f->fu_pipe_pd)) < 0) { logerror(f->fu_pipe_pname); break; } } if (writev(f->f_file, il->iov, il->iovcnt) < 0) { - int e = errno; - - deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname); - close_filed(f); - errno = e; logerror(f->fu_pipe_pname); + close_filed(f); } break; @@ -2260,7 +2260,7 @@ static void reapchild(int signo __unused) { int status; - pid_t pid; + pid_t pid, pipe_pid; struct filed *f; while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) { @@ -2270,8 +2270,16 @@ reapchild(int signo __unused) /* Now, look in list of active processes. */ STAILQ_FOREACH(f, &fhead, next) { - if (f->f_type == F_PIPE && - f->fu_pipe_pid == pid) { + if (f->f_type == F_PIPE) { + if (pdgetpid(f->fu_pipe_pd, &pipe_pid) == -1) { + dprintf("Failed to query PID: %s\n", + strerror(errno)); + continue; + } + if (pipe_pid != pid) + continue; + /* Do not enter into deadq. */ + f->fu_pipe_pd = -1; close_filed(f); log_deadchild(pid, status, f->fu_pipe_pname); break; @@ -2352,7 +2360,8 @@ die(int signo) /* flush any pending output */ if (f->f_prevcount) fprintlog_successive(f, 0); - if (f->f_type == F_PIPE && f->fu_pipe_pid > 0) + /* close our end of the pipe */ + if (f->f_type == F_PIPE) close_filed(f); } if (signo) { @@ -2608,7 +2617,6 @@ init(bool reload) close_filed(f); break; case F_PIPE: - deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname); close_filed(f); break; default: @@ -3135,7 +3143,7 @@ cfline(const char *line, const char *prog, const char *host, break; case '|': - f->fu_pipe_pid = 0; + f->fu_pipe_pd = -1; (void)strlcpy(f->fu_pipe_pname, p + 1, sizeof(f->fu_pipe_pname)); f->f_type = F_PIPE; @@ -3220,7 +3228,7 @@ markit(void) switch (dq->dq_timeout) { case 0: /* Already signalled once, try harder now. */ - if (kill(dq->dq_pid, SIGKILL) != 0) + if (pdkill(dq->dq_procdesc, SIGKILL) != 0) (void)deadq_remove(dq); break; @@ -3233,7 +3241,7 @@ markit(void) * didn't even really exist, in case we simply * drop it from the dead queue). */ - if (kill(dq->dq_pid, SIGTERM) != 0) + if (pdkill(dq->dq_procdesc, SIGTERM) != 0) (void)deadq_remove(dq); else dq->dq_timeout--; @@ -3610,10 +3618,10 @@ validate(struct sockaddr *sa, const char *hname) * opposed to a FILE *. */ static int -p_open(const char *prog, pid_t *rpid) +p_open(const char *prog, int *rpd) { sigset_t sigset = { }; - int pfd[2], nulldesc; + int nulldesc, pfd[2], pd; pid_t pid; char *argv[4]; /* sh -c cmd NULL */ char errmsg[200]; @@ -3624,7 +3632,7 @@ p_open(const char *prog, pid_t *rpid) /* we are royally screwed anyway */ return (-1); - switch ((pid = fork())) { + switch ((pid = pdfork(&pd, PD_CLOEXEC))) { case -1: close(nulldesc); return (-1); @@ -3676,63 +3684,54 @@ p_open(const char *prog, pid_t *rpid) (int)pid); logerror(errmsg); } - *rpid = pid; + *rpd = pd; return (pfd[1]); } static void -deadq_enter(pid_t pid, const char *name) +deadq_enter(int pd) { struct deadq_entry *dq; - int status; - if (pid == 0) + if (pd == -1) return; - /* - * Be paranoid, if we can't signal the process, don't enter it - * into the dead queue (perhaps it's already dead). If possible, - * we try to fetch and log the child's status. - */ - if (kill(pid, 0) != 0) { - if (waitpid(pid, &status, WNOHANG) > 0) - log_deadchild(pid, status, name); - return; - } dq = malloc(sizeof(*dq)); if (dq == NULL) { logerror("malloc"); exit(1); } - *dq = (struct deadq_entry){ - .dq_pid = pid, - .dq_timeout = DQ_TIMO_INIT - }; + + dq->dq_procdesc = pd; + dq->dq_timeout = DQ_TIMO_INIT; TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries); } -static int +static void deadq_remove(struct deadq_entry *dq) { - if (dq != NULL) { - TAILQ_REMOVE(&deadq_head, dq, dq_entries); - free(dq); - return (1); - } - - return (0); + TAILQ_REMOVE(&deadq_head, dq, dq_entries); + close(dq->dq_procdesc); + free(dq); } -static int +static bool deadq_removebypid(pid_t pid) { struct deadq_entry *dq; + pid_t dq_pid; TAILQ_FOREACH(dq, &deadq_head, dq_entries) { - if (dq->dq_pid == pid) - break; + if (pdgetpid(dq->dq_procdesc, &dq_pid) == -1) { + dprintf("Failed to query PID: %s\n", strerror(errno)); + continue; + } + if (dq_pid == pid) { + deadq_remove(dq); + return (true); + } } - return (deadq_remove(dq)); + return (false); } static void