Index | Thread | Search

From:
Stuart Henderson <stu@spacehopper.org>
Subject:
Re: syslogd separate parent program
To:
renaud@openbsd.org
Cc:
tech@openbsd.org
Date:
Sun, 7 Jun 2026 19:11:33 +0100

Download raw body.

Thread
  • renaud@openbsd.org:

    syslogd separate parent program

    • Stuart Henderson:

      syslogd separate parent program

  • On 2026/06/07 19:32, renaud@openbsd.org wrote:
    > 
    > 
    > On 07/06/2026 18:29, Alexander Bluhm wrote:
    > > Hi,
    > > 
    > > syslogd forks and execs its parent process to keep privileged parts
    > > separated.  This parent process can be easily implemented as a
    > > separate program.  Then its process image is smaller, especially
    > > without additional libs.
    > > 
    > > The new parent got its own main() and a minimal debug log function.
    > > 
    > > ok?
    > > 
    > 
    > Maybe just a small warning in release notes that scripts using pkill/pgrep
    > -x won't match syslogd-parent
    
    does it matter? (apart from anything else the standard interface for
    doing this would be the rc.d script..)
    
    > > bluhm
    > > 
    > > Index: usr.sbin/syslogd/Makefile
    > > ===================================================================
    > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/Makefile,v
    > > diff -u -p -r1.9 Makefile
    > > --- usr.sbin/syslogd/Makefile	13 Jan 2022 10:34:07 -0000	1.9
    > > +++ usr.sbin/syslogd/Makefile	6 Jun 2026 20:42:37 -0000
    > > @@ -1,10 +1,14 @@
    > >   #	$OpenBSD: Makefile,v 1.9 2022/01/13 10:34:07 martijn Exp $
    > > -PROG=	syslogd
    > > -SRCS=	evbuffer_tls.c log.c parsemsg.c privsep.c privsep_fdpass.c ringbuf.c \
    > > -	syslogd.c ttymsg.c
    > > -MAN=	syslogd.8 syslog.conf.5
    > > -LDADD=	-levent -ltls -lssl -lcrypto
    > > -DPADD=	${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
    > > +PROGS=		syslogd syslogd-parent
    > > +
    > > +SRCS_syslogd=	evbuffer_tls.c log.c parsemsg.c privsep.c \
    > > +		privsep_fdpass.c ringbuf.c syslogd.c ttymsg.c
    > > +LDADD_syslogd=	-levent -ltls -lssl -lcrypto
    > > +DPADD_syslogd=	${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
    > > +
    > > +SRCS_syslogd-parent=	parent.c privsep.c privsep_fdpass.c
    > > +
    > > +MAN=		syslogd.8 syslog.conf.5
    > >   .include <bsd.prog.mk>
    > > Index: usr.sbin/syslogd/parent.c
    > > ===================================================================
    > > RCS file: usr.sbin/syslogd/parent.c
    > > diff -N usr.sbin/syslogd/parent.c
    > > --- /dev/null	1 Jan 1970 00:00:00 -0000
    > > +++ usr.sbin/syslogd/parent.c	7 Jun 2026 16:13:52 -0000
    > > @@ -0,0 +1,136 @@
    > > +/*	$OpenBSD$	*/
    > > +
    > > +/*
    > > + * Copyright (c) 2026 Alexander Bluhm <bluhm@openbsd.org>
    > > + *
    > > + * Permission to use, copy, modify, and distribute this software for any
    > > + * purpose with or without fee is hereby granted, provided that the above
    > > + * copyright notice and this permission notice appear in all copies.
    > > + *
    > > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    > > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    > > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    > > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    > > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    > > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    > > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    > > + */
    > > +
    > > +#include <err.h>
    > > +#include <errno.h>
    > > +#include <limits.h>
    > > +#include <paths.h>
    > > +#include <stdio.h>
    > > +#include <stdlib.h>
    > > +#include <syslog.h>
    > > +#include <unistd.h>
    > > +
    > > +#include "log.h"
    > > +#include "syslogd.h"
    > > +
    > > +static int	 verbose;
    > > +static char	*debug_ebuf;
    > > +
    > > +/* parent process is re-execed with reduced arguments, others ignored */
    > > +
    > > +static __dead void
    > > +usage(void)
    > > +{
    > > +	(void)fprintf(stderr,
    > > +	    "usage: syslogd-parent [-dn] [-f config_file] -P child_pid\n");
    > > +	exit(1);
    > > +}
    > > +
    > > +int
    > > +main(int argc, char *argv[])
    > > +{
    > > +	char *ConfFile = _PATH_LOGCONF;
    > > +	int Debug = 0;
    > > +	int PrivChild = 0;
    > > +	int NoDNS = 0;
    > > +	const char *errstr;
    > > +	int ch;
    > > +
    > > +	while ((ch = getopt(argc, argv,
    > > +	    "46a:C:c:dFf:hK:k:m:nP:p:rS:s:T:U:uVZ")) != -1) {
    > > +		switch (ch) {
    > > +		case '4':
    > > +		case '6':
    > > +		case 'a':
    > > +		case 'C':
    > > +		case 'c':
    > > +		case 'd':		/* debug */
    > > +			Debug++;
    > > +			break;
    > > +		case 'F':
    > > +			break;
    > > +		case 'f':		/* configuration file */
    > > +			ConfFile = optarg;
    > > +			break;
    > > +		case 'h':
    > > +		case 'K':
    > > +		case 'k':
    > > +		case 'm':
    > > +			break;
    > > +		case 'n':		/* don't do DNS lookups */
    > > +			NoDNS = 1;
    > > +			break;
    > > +		case 'P':		/* used internally, exec the parent */
    > > +			PrivChild = strtonum(optarg, 2, INT_MAX, &errstr);
    > > +			if (errstr)
    > > +				errx(1, "priv child %s: %s", errstr, optarg);
    > > +			break;
    > > +		case 'p':
    > > +		case 'r':
    > > +		case 'S':
    > > +		case 's':
    > > +		case 'T':
    > > +		case 'U':
    > > +		case 'u':
    > > +		case 'V':
    > > +		case 'Z':
    > > +			break;
    > > +		default:
    > > +			usage();
    > > +		}
    > > +	}
    > > +	if (argc != optind)
    > > +		usage();
    > > +	if (PrivChild < 2)
    > > +		errx(1, "parent requires -P child_pid");
    > > +
    > > +	log_init(Debug, LOG_SYSLOG);
    > > +	priv_exec(ConfFile, NoDNS, PrivChild, argc, argv);
    > > +
    > > +	/* NOTREACHED */
    > > +	return 1;
    > > +}
    > > +
    > > +void
    > > +log_init(int n_debug, int fac)
    > > +{
    > > +	verbose = n_debug;
    > > +
    > > +	if (debug_ebuf == NULL)
    > > +		if ((debug_ebuf = malloc(ERRBUFSIZE)) == NULL)
    > > +		    err(1, "allocate debug buffer");
    > > +	debug_ebuf[0] = '\0';
    > > +}
    > > +
    > > +void
    > > +log_debug(const char *emsg, ...)
    > > +{
    > > +	va_list ap;
    > > +	int saved_errno;
    > > +
    > > +	if (verbose) {
    > > +		saved_errno = errno;
    > > +		va_start(ap, emsg);
    > > +		vsnprintf(debug_ebuf, ERRBUFSIZE, emsg, ap);
    > > +		fprintf(stderr, "[priv]: %s\n", debug_ebuf);
    > > +		fflush(stderr);
    > > +		va_end(ap);
    > > +		errno = saved_errno;
    > > +	}
    > > +	debug_ebuf[0] = '\0';
    > > +}
    > > Index: usr.sbin/syslogd/privsep.c
    > > ===================================================================
    > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/privsep.c,v
    > > diff -u -p -r1.77 privsep.c
    > > --- usr.sbin/syslogd/privsep.c	12 Oct 2023 22:36:54 -0000	1.77
    > > +++ usr.sbin/syslogd/privsep.c	7 Jun 2026 16:14:05 -0000
    > > @@ -96,10 +96,10 @@ static int  may_read(int, void *, size_t
    > >   static struct passwd *pw;
    > >   void
    > > -priv_init(int lockfd, int nullfd, int argc, char *argv[])
    > > +priv_init(int debug, int lockfd, int nullfd, int argc, char *argv[])
    > >   {
    > >   	int i, socks[2];
    > > -	char *execpath, childnum[11], **privargv;
    > > +	char childnum[11], **privargv;
    > >   	/* Create sockets */
    > >   	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
    > > @@ -132,14 +132,10 @@ priv_init(int lockfd, int nullfd, int ar
    > >   	}
    > >   	close(socks[1]);
    > > -	if (strchr(argv[0], '/') == NULL)
    > > -		execpath = argv[0];
    > > -	else if ((execpath = realpath(argv[0], NULL)) == NULL)
    > > -		err(1, "realpath %s", argv[0]);
    > >   	if (chdir("/") != 0)
    > >   		err(1, "chdir /");
    > > -	if (!Debug) {
    > > +	if (!debug) {
    > >   		close(lockfd);
    > >   		dup2(nullfd, STDIN_FILENO);
    > >   		dup2(nullfd, STDOUT_FILENO);
    > > @@ -156,18 +152,18 @@ priv_init(int lockfd, int nullfd, int ar
    > >   	snprintf(childnum, sizeof(childnum), "%d", child_pid);
    > >   	if ((privargv = reallocarray(NULL, argc + 3, sizeof(char *))) == NULL)
    > >   		err(1, "alloc priv argv failed");
    > > -	privargv[0] = execpath;
    > > +	privargv[0] = "/usr/sbin/syslogd-parent";
    > >   	for (i = 1; i < argc; i++)
    > >   		privargv[i] = argv[i];
    > >   	privargv[i++] = "-P";
    > >   	privargv[i++] = childnum;
    > >   	privargv[i++] = NULL;
    > > -	execvp(privargv[0], privargv);
    > > +	execv(privargv[0], privargv);
    > >   	err(1, "exec priv '%s' failed", privargv[0]);
    > >   }
    > >   __dead void
    > > -priv_exec(char *conf, int numeric, int child, int argc, char *argv[])
    > > +priv_exec(const char *conf, int numeric, int child, int argc, char *argv[])
    > >   {
    > >   	int i, fd, sock, cmd, addr_len, result, restart;
    > >   	size_t path_len, protoname_len, hostname_len, servname_len;
    > > @@ -235,7 +231,7 @@ priv_exec(char *conf, int numeric, int c
    > >   	sigaction(SIGCHLD, &sa, NULL);
    > >   	setproctitle("[priv]");
    > > -	log_debug("[priv]: fork+exec done");
    > > +	log_debug("fork+exec done");
    > >   	sigemptyset(&sigmask);
    > >   	if (sigprocmask(SIG_SETMASK, &sigmask, NULL) == -1)
    > > @@ -253,7 +249,7 @@ priv_exec(char *conf, int numeric, int c
    > >   			break;
    > >   		switch (cmd) {
    > >   		case PRIV_OPEN_TTY:
    > > -			log_debug("[priv]: msg PRIV_OPEN_TTY received");
    > > +			log_debug("msg PRIV_OPEN_TTY received");
    > >   			/* Expecting: length, path */
    > >   			must_read(sock, &path_len, sizeof(size_t));
    > >   			if (path_len == 0 || path_len > sizeof(path))
    > > @@ -271,7 +267,7 @@ priv_exec(char *conf, int numeric, int c
    > >   		case PRIV_OPEN_LOG:
    > >   		case PRIV_OPEN_PIPE:
    > > -			log_debug("[priv]: msg PRIV_OPEN_%s received",
    > > +			log_debug("msg PRIV_OPEN_%s received",
    > >   			    cmd == PRIV_OPEN_PIPE ? "PIPE" : "LOG");
    > >   			/* Expecting: length, path */
    > >   			must_read(sock, &path_len, sizeof(size_t));
    > > @@ -296,7 +292,7 @@ priv_exec(char *conf, int numeric, int c
    > >   			break;
    > >   		case PRIV_OPEN_UTMP:
    > > -			log_debug("[priv]: msg PRIV_OPEN_UTMP received");
    > > +			log_debug("msg PRIV_OPEN_UTMP received");
    > >   			fd = open(_PATH_UTMP, O_RDONLY|O_NONBLOCK);
    > >   			send_fd(sock, fd);
    > >   			if (fd == -1)
    > > @@ -306,7 +302,7 @@ priv_exec(char *conf, int numeric, int c
    > >   			break;
    > >   		case PRIV_OPEN_CONFIG:
    > > -			log_debug("[priv]: msg PRIV_OPEN_CONFIG received");
    > > +			log_debug("msg PRIV_OPEN_CONFIG received");
    > >   			stat(conf, &cf_info);
    > >   			fd = open(conf, O_RDONLY|O_NONBLOCK);
    > >   			send_fd(sock, fd);
    > > @@ -317,7 +313,7 @@ priv_exec(char *conf, int numeric, int c
    > >   			break;
    > >   		case PRIV_CONFIG_MODIFIED:
    > > -			log_debug("[priv]: msg PRIV_CONFIG_MODIFIED received");
    > > +			log_debug("msg PRIV_CONFIG_MODIFIED received");
    > >   			if (stat(conf, &cf_stat) == -1 ||
    > >   			    timespeccmp(&cf_info.st_mtim,
    > >   			    &cf_stat.st_mtim, <) ||
    > > @@ -335,13 +331,13 @@ priv_exec(char *conf, int numeric, int c
    > >   			if (pledge("stdio rpath wpath cpath dns sendfd id proc exec",
    > >   			    NULL) == -1)
    > >   				err(1, "pledge done config");
    > > -			log_debug("[priv]: msg PRIV_DONE_CONFIG_PARSE "
    > > +			log_debug("msg PRIV_DONE_CONFIG_PARSE "
    > >   			    "received");
    > >   			increase_state(STATE_RUNNING);
    > >   			break;
    > >   		case PRIV_GETADDRINFO:
    > > -			log_debug("[priv]: msg PRIV_GETADDRINFO received");
    > > +			log_debug("msg PRIV_GETADDRINFO received");
    > >   			/* Expecting: len, proto, len, host, len, serv */
    > >   			must_read(sock, &protoname_len, sizeof(size_t));
    > >   			if (protoname_len == 0 ||
    > > @@ -407,7 +403,7 @@ priv_exec(char *conf, int numeric, int c
    > >   			break;
    > >   		case PRIV_GETNAMEINFO:
    > > -			log_debug("[priv]: msg PRIV_GETNAMEINFO received");
    > > +			log_debug("msg PRIV_GETNAMEINFO received");
    > >   			if (numeric)
    > >   				errx(1, "rejected attempt to getnameinfo");
    > >   			/* Expecting: length, sockaddr */
    > > @@ -442,7 +438,8 @@ priv_exec(char *conf, int numeric, int c
    > >   		sigaddset(&sigmask, SIGHUP);
    > >   		if (sigprocmask(SIG_SETMASK, &sigmask, NULL) == -1)
    > >   			err(1, "sigprocmask exec");
    > > -		execvp(argv[0], argv);
    > > +		argv[0] = "/usr/sbin/syslogd";
    > > +		execv(argv[0], argv);
    > >   		err(1, "exec restart '%s' failed", argv[0]);
    > >   	}
    > >   	unlink(_PATH_LOGPID);
    > > Index: usr.sbin/syslogd/syslogd.c
    > > ===================================================================
    > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
    > > diff -u -p -r1.287 syslogd.c
    > > --- usr.sbin/syslogd/syslogd.c	26 Jun 2025 19:10:13 -0000	1.287
    > > +++ usr.sbin/syslogd/syslogd.c	7 Jun 2026 16:14:05 -0000
    > > @@ -121,7 +121,7 @@
    > >   #include "evbuffer_tls.h"
    > >   #include "parsemsg.h"
    > > -char *ConfFile = _PATH_LOGCONF;
    > > +const char *ConfFile = _PATH_LOGCONF;
    > >   const char ctty[] = _PATH_CONSOLE;
    > >   #define MAXUNAMES	20	/* maximum number of user names */
    > > @@ -226,7 +226,6 @@ int	Initialized = 0;	/* set when we have
    > >   int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
    > >   int	MarkSeq = 0;		/* mark sequence number */
    > > -int	PrivChild = 0;		/* Exec the privileged parent process */
    > >   int	Repeat = 0;		/* 0 msg repeated, 1 in files only, 2 never */
    > >   int	SecureMode = 1;		/* when true, speak only unix domain socks */
    > >   int	NoDNS = 0;		/* when true, refrain from doing DNS lookups */
    > > @@ -350,7 +349,6 @@ struct filed *find_dup(struct filed *);
    > >   void	printline(char *, char *);
    > >   void	printsys(char *);
    > >   void	current_time(char *);
    > > -void	usage(void);
    > >   void	wallmsg(struct filed *, struct iovec *);
    > >   int	loghost_parse(char *, char **, char **, char **);
    > >   int	getmsgbufsize(void);
    > > @@ -363,6 +361,17 @@ void	set_sockbuf(int);
    > >   void	set_keepalive(int);
    > >   void	tailify_replytext(char *, int);
    > > +static __dead void
    > > +usage(void)
    > > +{
    > > +	(void)fprintf(stderr,
    > > +	    "usage: syslogd [-46dFhnruVZ] [-a path] [-C CAfile]\n"
    > > +	    "\t[-c cert_file] [-f config_file] [-K CAfile] [-k key_file]\n"
    > > +	    "\t[-m mark_interval] [-p log_socket] [-S listen_address]\n"
    > > +	    "\t[-s reporting_socket] [-T listen_address] [-U bind_address]\n");
    > > +	exit(1);
    > > +}
    > > +
    > >   int
    > >   main(int argc, char *argv[])
    > >   {
    > > @@ -399,7 +408,7 @@ main(int argc, char *argv[])
    > >   	nbind = nlisten = ntls = 0;
    > >   	while ((ch = getopt(argc, argv,
    > > -	    "46a:C:c:dFf:hK:k:m:nP:p:rS:s:T:U:uVZ")) != -1) {
    > > +	    "46a:C:c:dFf:hK:k:m:np:rS:s:T:U:uVZ")) != -1) {
    > >   		switch (ch) {
    > >   		case '4':		/* disable IPv6 */
    > >   			Family = PF_INET;
    > > @@ -446,11 +455,6 @@ main(int argc, char *argv[])
    > >   		case 'n':		/* don't do DNS lookups */
    > >   			NoDNS = 1;
    > >   			break;
    > > -		case 'P':		/* used internally, exec the parent */
    > > -			PrivChild = strtonum(optarg, 2, INT_MAX, &errstr);
    > > -			if (errstr)
    > > -				errx(1, "priv child %s: %s", errstr, optarg);
    > > -			break;
    > >   		case 'p':		/* path */
    > >   			path_unix[0] = optarg;
    > >   			break;
    > > @@ -503,9 +507,6 @@ main(int argc, char *argv[])
    > >   				fatal("dup2 null");
    > >   	}
    > > -	if (PrivChild > 1)
    > > -		priv_exec(ConfFile, NoDNS, PrivChild, argc, argv);
    > > -
    > >   	consfile.f_type = F_CONSOLE;
    > >   	(void)strlcpy(consfile.f_un.f_fname, ctty,
    > >   	    sizeof(consfile.f_un.f_fname));
    > > @@ -757,7 +758,7 @@ main(int argc, char *argv[])
    > >   	}
    > >   	/* Privilege separation begins here */
    > > -	priv_init(lockpipe[1], nullfd, argc, argv);
    > > +	priv_init(Debug, lockpipe[1], nullfd, argc, argv);
    > >   	if (pledge("stdio unix inet recvfd", NULL) == -1)
    > >   		err(1, "pledge");
    > > @@ -1662,18 +1663,6 @@ tcpbuf_countmsg(struct bufferevent *bufe
    > >   			i++;
    > >   	}
    > >   	return (i);
    > > -}
    > > -
    > > -void
    > > -usage(void)
    > > -{
    > > -
    > > -	(void)fprintf(stderr,
    > > -	    "usage: syslogd [-46dFhnruVZ] [-a path] [-C CAfile]\n"
    > > -	    "\t[-c cert_file] [-f config_file] [-K CAfile] [-k key_file]\n"
    > > -	    "\t[-m mark_interval] [-p log_socket] [-S listen_address]\n"
    > > -	    "\t[-s reporting_socket] [-T listen_address] [-U bind_address]\n");
    > > -	exit(1);
    > >   }
    > >   /*
    > > Index: usr.sbin/syslogd/syslogd.h
    > > ===================================================================
    > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.h,v
    > > diff -u -p -r1.37 syslogd.h
    > > --- usr.sbin/syslogd/syslogd.h	12 Oct 2023 22:36:54 -0000	1.37
    > > +++ usr.sbin/syslogd/syslogd.h	7 Jun 2026 16:14:05 -0000
    > > @@ -26,8 +26,8 @@
    > >   extern int	ZuluTime;
    > >   /* Privilege separation */
    > > -void  priv_init(int, int, int, char **);
    > > -__dead void priv_exec(char *, int, int, int, char **);
    > > +void  priv_init(int, int, int, int, char **);
    > > +__dead void priv_exec(const char *, int, int, int, char **);
    > >   int   priv_open_tty(const char *);
    > >   int   priv_open_log(const char *);
    > >   FILE *priv_open_utmp(void);
    > > @@ -52,7 +52,6 @@ int  receive_fd(int);
    > >   #define ERRBUFSIZE	256
    > >   void vlogmsg(int pri, const char *, const char *, va_list);
    > >   __dead void die(int);
    > > -extern int Debug;
    > >   struct ringbuf {
    > >   	char *buf;
    > > Index: etc/rc.d/syslogd
    > > ===================================================================
    > > RCS file: /data/mirror/openbsd/cvs/src/etc/rc.d/syslogd,v
    > > diff -u -p -r1.5 syslogd
    > > --- etc/rc.d/syslogd	11 Jan 2018 19:52:12 -0000	1.5
    > > +++ etc/rc.d/syslogd	7 Jun 2026 08:58:14 -0000
    > > @@ -6,7 +6,7 @@ daemon="/usr/sbin/syslogd"
    > >   . /etc/rc.d/rc.subr
    > > -pexp="syslogd: \[priv\]"
    > > +pexp="syslogd-parent: \[priv\]"
    > >   rc_pre() {
    > >   	rm -f /dev/log
    > > 
    > 
    
    
  • renaud@openbsd.org:

    syslogd separate parent program