1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-17 23:03:29 +02:00

Provide a separate executable file for syslogd parent.

syslogd(8) forks and execs its parent process to keep privileged
parts separated.  This parent process can be easily implemented as
a separate program.  It gets its own main() and minimal debug logging
functions.  The splitted parent process image is smaller, especially
without additional libs.
Use additional directories to build both parts.  The rcctl script
has to be adopted, as the parent process has a different name.

OK deraadt@
This commit is contained in:
bluhm
2026-06-11 15:41:33 +00:00
parent 7238ecfd40
commit 13d1fa1150
9 changed files with 204 additions and 61 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
#!/bin/ksh
#
# $OpenBSD: syslogd,v 1.5 2018/01/11 19:52:12 rpe Exp $
# $OpenBSD: syslogd,v 1.6 2026/06/11 15:41:33 bluhm Exp $
daemon="/usr/sbin/syslogd"
. /etc/rc.d/rc.subr
pexp="syslogd: \[priv\]"
pexp="syslogd-parent: \[priv\]"
rc_pre() {
rm -f /dev/log
+5 -8
View File
@@ -1,10 +1,7 @@
# $OpenBSD: Makefile,v 1.9 2022/01/13 10:34:07 martijn Exp $
# $OpenBSD: Makefile,v 1.10 2026/06/11 15:41:33 bluhm 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}
.include <bsd.own.mk>
.include <bsd.prog.mk>
SUBDIR= syslogd parent
.include <bsd.subdir.mk>
+4
View File
@@ -0,0 +1,4 @@
# $OpenBSD: Makefile.inc,v 1.1 2026/06/11 15:41:33 bluhm Exp $
BINDIR?= /usr/sbin
COPTS+= -Werror-implicit-function-declaration
+136
View File
@@ -0,0 +1,136 @@
/* $OpenBSD: parent.c,v 1.1 2026/06/11 15:41:33 bluhm Exp $ */
/*
* 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';
}
+9
View File
@@ -0,0 +1,9 @@
# $OpenBSD: Makefile,v 1.1 2026/06/11 15:41:33 bluhm Exp $
.PATH: ${.CURDIR}/..
PROG= syslogd-parent
SRCS= parent.c privsep.c privsep_fdpass.c
NOMAN= Yes
.include <bsd.prog.mk>
+18 -21
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: privsep.c,v 1.77 2023/10/12 22:36:54 bluhm Exp $ */
/* $OpenBSD: privsep.c,v 1.78 2026/06/11 15:41:33 bluhm Exp $ */
/*
* Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
@@ -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 argc, char *argv[])
}
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 argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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 child, int argc, char *argv[])
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);
+15 -26
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: syslogd.c,v 1.287 2025/06/26 19:10:13 bluhm Exp $ */
/* $OpenBSD: syslogd.c,v 1.288 2026/06/11 15:41:33 bluhm Exp $ */
/*
* Copyright (c) 2014-2021 Alexander Bluhm <bluhm@genua.de>
@@ -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 initialized ourselves */
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");
@@ -1664,18 +1665,6 @@ tcpbuf_countmsg(struct bufferevent *bufev)
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);
}
/*
* Take a raw input line, decode the message, and print the message
* on the appropriate log files.
+3 -4
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: syslogd.h,v 1.37 2023/10/12 22:36:54 bluhm Exp $ */
/* $OpenBSD: syslogd.h,v 1.38 2026/06/11 15:41:33 bluhm Exp $ */
/*
* Copyright (c) 2014-2017 Alexander Bluhm <bluhm@genua.de>
@@ -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;
+12
View File
@@ -0,0 +1,12 @@
# $OpenBSD: Makefile,v 1.1 2026/06/11 15:41:33 bluhm Exp $
.PATH: ${.CURDIR}/..
PROG= syslogd
SRCS= evbuffer_tls.c log.c parsemsg.c privsep.c \
privsep_fdpass.c ringbuf.c syslogd.c ttymsg.c
LDADD= -levent -ltls -lssl -lcrypto
DPADD= ${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
MAN= syslogd.8 syslog.conf.5
.include <bsd.prog.mk>