Re: dhcpcd 9.3.1 timing out on Arch Linux ARM
Roy Marples
Fri Oct 30 14:39:09 2020
On 30/10/2020 13:30, Adolf Belka wrote:
Hi Roy,
Patches I can run against an existing install but I am afraid I don't know how
to go about testing the current git master. I did some googling and it looks
like I need to clone your git repository and then build dhcpcd but I am not sure
then how to replace my distributions dhcpcd with the git one to test it, without
messing everything up.
I've attached a patch to bring dhcpcd-9.3.1 up to the current master.
Let me know how it works - I'm pretty confident because another ARM user just
reported success :)
Roy
diff --git a/src/dhcp.c b/src/dhcp.c
index cbfb2bc8..2b741385 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -2926,6 +2926,8 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
unsigned int i;
char *msg;
bool bootp_copied;
+ uint32_t v6only_time = 0;
+ bool use_v6only = false;
#ifdef AUTH
const uint8_t *auth;
size_t auth_len;
@@ -3143,6 +3145,23 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
}
}
+ if (has_option_mask(ifo->requestmask, DHO_IPV6_PREFERRED_ONLY)) {
+ if (get_option_uint32(ifp->ctx, &v6only_time, bootp, bootp_len,
+ DHO_IPV6_PREFERRED_ONLY) == 0 &&
+ (state->state == DHS_DISCOVER || state->state == DHS_REBOOT))
+ {
+ char v6msg[128];
+
+ use_v6only = true;
+ if (v6only_time < MIN_V6ONLY_WAIT)
+ v6only_time = MIN_V6ONLY_WAIT;
+ snprintf(v6msg, sizeof(v6msg),
+ "IPv6-Only Preferred received (%u seconds)",
+ v6only_time);
+ LOGDHCP(LOG_INFO, v6msg);
+ }
+ }
+
/* DHCP Auto-Configure, RFC 2563 */
if (type == DHCP_OFFER && bootp->yiaddr == 0) {
LOGDHCP(LOG_WARNING, "no address given");
@@ -3177,12 +3196,22 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
}
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
- DHCP_MAX, dhcp_discover, ifp);
+ use_v6only ? v6only_time : DHCP_MAX,
+ dhcp_discover, ifp);
}
#endif
return;
}
+ if (use_v6only) {
+ dhcp_drop(ifp, "EXPIRE");
+ dhcp_unlink(ifp->ctx, state->leasefile);
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ eloop_timeout_add_sec(ifp->ctx->eloop, v6only_time,
+ dhcp_discover, ifp);
+ return;
+ }
+
/* Ensure that the address offered is valid */
if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
(bootp->ciaddr == INADDR_ANY || bootp->ciaddr == INADDR_BROADCAST)
diff --git a/src/dhcp.h b/src/dhcp.h
index 497e2888..d0f569d5 100644
--- a/src/dhcp.h
+++ b/src/dhcp.h
@@ -116,6 +116,7 @@ enum DHO {
DHO_RAPIDCOMMIT = 80, /* RFC 4039 */
DHO_FQDN = 81,
DHO_AUTHENTICATION = 90, /* RFC 3118 */
+ DHO_IPV6_PREFERRED_ONLY = 108, /* RFC 8925 */
DHO_AUTOCONFIGURE = 116, /* RFC 2563 */
DHO_DNSSEARCH = 119, /* RFC 3397 */
DHO_CSR = 121, /* RFC 3442 */
@@ -139,6 +140,8 @@ enum FQDN {
FQDN_BOTH = 0x31
};
+#define MIN_V6ONLY_WAIT 300 /* seconds, RFC 8925 */
+
/* Sizes for BOOTP options */
#define BOOTP_CHADDR_LEN 16
#define BOOTP_SNAME_LEN 64
diff --git a/src/dhcpcd-definitions.conf b/src/dhcpcd-definitions.conf
index d0b64314..38870091 100644
--- a/src/dhcpcd-definitions.conf
+++ b/src/dhcpcd-definitions.conf
@@ -172,6 +172,9 @@ define 101 string tzdb_timezone
# Options 102-115 are unused, RFC3679
+# DHCP IPv6-Only Preferred, RFC8925
+define 108 uint32 ipv6_only_preferred
+
# DHCP Auto-Configuration, RFC2563
define 116 byte auto_configure
diff --git a/src/dhcpcd.8.in b/src/dhcpcd.8.in
index 9309250a..50964565 100644
--- a/src/dhcpcd.8.in
+++ b/src/dhcpcd.8.in
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 2, 2020
+.Dd October 30, 2020
.Dt DHCPCD 8
.Os
.Sh NAME
@@ -846,13 +846,5 @@ RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@xxxxxxxxxxxx
.Sh BUGS
-If
-.Nm
-is running in a
-.Xr chroot 2
-then re-opening the
-.Fl Fl logfile
-from SIGUSR2 may not work.
-.Pp
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index 9b0a79a4..169aeec1 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -1422,10 +1422,14 @@ dhcpcd_signal_cb(int sig, void *arg)
return;
case SIGUSR2:
loginfox(sigmsg, "SIGUSR2", "reopening log");
- /* XXX This may not work that well in a chroot */
- logclose();
- if (logopen(ctx->logfile) == -1)
- logerr(__func__);
+ if (IN_PRIVSEP(ctx)) {
+ if (ps_root_logreopen(ctx) == -1)
+ logerr("ps_root_logreopen");
+ } else {
+ logclose();
+ if (logopen(ctx->logfile) == -1)
+ logerr("logopen");
+ }
return;
case SIGCHLD:
while (waitpid(-1, NULL, WNOHANG) > 0)
@@ -1860,7 +1864,7 @@ main(int argc, char **argv, char **envp)
ctx.dhcp6_wfd = -1;
#endif
#ifdef PRIVSEP
- ctx.ps_root_fd = ctx.ps_data_fd = -1;
+ ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1;
ctx.ps_inet_fd = ctx.ps_control_fd = -1;
TAILQ_INIT(&ctx.ps_processes);
#endif
@@ -2328,6 +2332,7 @@ printpidfile:
/* We have now forked, setsid, forked once more.
* From this point on, we are the controlling daemon. */
ctx.options |= DHCPCD_STARTED;
+ logdebugx("spawned master process on PID %d", getpid());
if ((pid = pidfile_lock(ctx.pidfile)) != 0) {
logerr("%s: pidfile_lock %d", __func__, pid);
#ifdef PRIVSEP
diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in
index 1169ae7a..1e7a8631 100644
--- a/src/dhcpcd.conf.5.in
+++ b/src/dhcpcd.conf.5.in
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 28, 2020
+.Dd October 25, 2020
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@@ -606,18 +606,24 @@ Suppress any dhcpcd output to the console, except for errors.
.It Ic reboot Ar seconds
Allow
.Ar reboot
-seconds before moving to the DISCOVER phase if we have an old lease to use
-and moving from DISCOVER to IPv4LL if no reply.
+seconds before moving to the DISCOVER phase if we have an old lease to use.
+Allow
+.Ar reboot
+seconds before starting fallback states from the DISCOVER phase.
+IPv4LL is started when the first
+.Ar reboot
+timeout is reached.
The default is 5 seconds.
A setting of 0 seconds causes
-.Nm dhcpcd
-to skip the REBOOT phase and go straight into DISCOVER.
+.Nm
+to skip the reboot phase and go straight into DISCOVER.
This is desirable for mobile users because if you change from network A to
network B and they use the same subnet and the address from network A isn't
in use on network B, then the DHCP server will remain silent even if
authoritative which means
.Nm dhcpcd
will timeout before moving back to the DISCOVER phase.
+This has no effect on DHCPv6 other than skipping the reboot phase.
.It Ic release
.Nm dhcpcd
will release the lease prior to stopping the interface.
diff --git a/src/dhcpcd.h b/src/dhcpcd.h
index 8cdd3c19..97d7a322 100644
--- a/src/dhcpcd.h
+++ b/src/dhcpcd.h
@@ -199,6 +199,7 @@ struct dhcpcd_ctx {
struct passwd *ps_user; /* struct passwd for privsep user */
pid_t ps_root_pid;
int ps_root_fd; /* Privileged Actioneer commands */
+ int ps_log_fd; /* chroot logging */
int ps_data_fd; /* Data from root spawned processes */
struct eloop *ps_eloop; /* eloop for polling root data */
struct ps_process_head ps_processes; /* List of spawned processes */
diff --git a/src/if.c b/src/if.c
index 5f4edb86..deb5280b 100644
--- a/src/if.c
+++ b/src/if.c
@@ -198,10 +198,8 @@ if_is_link_up(const struct interface *ifp)
{
return ifp->flags & IFF_UP &&
- (ifp->carrier == LINK_UP ||
- (ifp->carrier == LINK_UNKNOWN &&
- !(ifp->options == NULL ||
- ifp->options->options & DHCPCD_LINK)));
+ (ifp->carrier != LINK_DOWN ||
+ (ifp->options != NULL && !(ifp->options->options & DHCPCD_LINK)));
}
int
diff --git a/src/logerr.c b/src/logerr.c
index ad337ba0..f407b2db 100644
--- a/src/logerr.c
+++ b/src/logerr.c
@@ -47,11 +47,16 @@
#undef LOGERR_TAG
#endif
+/* syslog protocol is 1k message max, RFC 3164 section 4.1 */
+#define LOGERR_SYSLOGBUF 1024 + sizeof(int) + sizeof(pid_t)
+
#define UNUSED(a) (void)(a)
struct logctx {
char log_buf[BUFSIZ];
unsigned int log_opts;
+ int log_fd;
+ pid_t log_pid;
#ifndef SMALL
FILE *log_file;
#ifdef LOGERR_TAG
@@ -63,9 +68,11 @@ struct logctx {
static struct logctx _logctx = {
/* syslog style, but without the hostname or tag. */
.log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID,
+ .log_fd = -1,
+ .log_pid = 0,
};
-#if defined(LOGERR_TAG) && defined(__linux__)
+#if defined(__linux__)
/* Poor man's getprogname(3). */
static char *_logprog;
static const char *
@@ -79,9 +86,12 @@ getprogname(void)
* so zero the buffer. */
if ((_logprog = calloc(1, PATH_MAX + 1)) == NULL)
return NULL;
+ if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1) {
+ free(_logprog);
+ _logprog = NULL;
+ return NULL;
+ }
}
- if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1)
- return NULL;
if (_logprog[0] == '[')
return NULL;
p = strrchr(_logprog, '/');
@@ -147,7 +157,13 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
(stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
if (log_pid) {
- if ((e = fprintf(stream, "[%d]", getpid())) == -1)
+ pid_t pid;
+
+ if (ctx->log_pid == 0)
+ pid = getpid();
+ else
+ pid = ctx->log_pid;
+ if ((e = fprintf(stream, "[%d]", pid)) == -1)
return -1;
len += e;
}
@@ -198,22 +214,37 @@ vlogmessage(int pri, const char *fmt, va_list args)
struct logctx *ctx = &_logctx;
int len = 0;
+ if (ctx->log_fd != -1) {
+ char buf[LOGERR_SYSLOGBUF];
+ pid_t pid;
+
+ memcpy(buf, &pri, sizeof(pri));
+ pid = getpid();
+ memcpy(buf + sizeof(pri), &pid, sizeof(pid));
+ len = vsnprintf(buf + sizeof(pri) + sizeof(pid),
+ sizeof(buf) - sizeof(pri) - sizeof(pid),
+ fmt, args);
+ if (len != -1)
+ len = (int)write(ctx->log_fd, buf,
+ ((size_t)++len) + sizeof(pri) + sizeof(pid));
+ return len;
+ }
+
if (ctx->log_opts & LOGERR_ERR &&
(pri <= LOG_ERR ||
(!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) ||
(ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG)))
len = vlogprintf_r(ctx, stderr, fmt, args);
- if (!(ctx->log_opts & LOGERR_LOG))
- return len;
-
#ifndef SMALL
if (ctx->log_file != NULL &&
(pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG)))
len = vlogprintf_r(ctx, ctx->log_file, fmt, args);
#endif
- vsyslog(pri, fmt, args);
+ if (ctx->log_opts & LOGERR_LOG)
+ vsyslog(pri, fmt, args);
+
return len;
}
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
@@ -331,6 +362,54 @@ log_errx(const char *fmt, ...)
va_end(args);
}
+int
+loggetfd(void)
+{
+ struct logctx *ctx = &_logctx;
+
+ return ctx->log_fd;
+}
+
+void
+logsetfd(int fd)
+{
+ struct logctx *ctx = &_logctx;
+
+ ctx->log_fd = fd;
+#ifndef SMALL
+ if (fd != -1 && ctx->log_file != NULL) {
+ fclose(ctx->log_file);
+ ctx->log_file = NULL;
+ }
+#endif
+}
+
+int
+logreadfd(int fd)
+{
+ struct logctx *ctx = &_logctx;
+ char buf[LOGERR_SYSLOGBUF];
+ int len, pri;
+
+ len = (int)read(fd, buf, sizeof(buf));
+ if (len == -1)
+ return -1;
+
+ /* Ensure we have pri, pid and a terminator */
+ if (len < (int)(sizeof(pri) + sizeof(pid_t) + 1) ||
+ buf[len - 1] != '\0')
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memcpy(&pri, buf, sizeof(pri));
+ memcpy(&ctx->log_pid, buf + sizeof(pri), sizeof(ctx->log_pid));
+ logmessage(pri, "%s", buf + sizeof(pri) + sizeof(ctx->log_pid));
+ ctx->log_pid = 0;
+ return len;
+}
+
unsigned int
loggetopts(void)
{
@@ -373,15 +452,9 @@ logopen(const char *path)
(void)setvbuf(stderr, ctx->log_buf, _IOLBF, sizeof(ctx->log_buf));
- if (!(ctx->log_opts & LOGERR_LOG))
- return 1;
-
-#ifdef LOG_NDELAY
- opts |= LOG_NDELAY;
-#endif
if (ctx->log_opts & LOGERR_LOG_PID)
opts |= LOG_PID;
- openlog(NULL, opts, LOGERR_SYSLOG_FACILITY);
+ openlog(getprogname(), opts, LOGERR_SYSLOG_FACILITY);
if (path == NULL)
return 1;
@@ -410,7 +483,7 @@ logclose(void)
fclose(ctx->log_file);
ctx->log_file = NULL;
#endif
-#if defined(LOGERR_TAG) && defined(__linux__)
+#if defined(__linux__)
free(_logprog);
#endif
}
diff --git a/src/logerr.h b/src/logerr.h
index 4b4d6dc4..baa43362 100644
--- a/src/logerr.h
+++ b/src/logerr.h
@@ -76,6 +76,11 @@ __printflike(2, 3) void logerrmessage(int pri, const char *fmt, ...);
#define logerr(...) log_err(__VA_ARGS__)
#define logerrx(...) log_errx(__VA_ARGS__)
+/* For logging in a chroot */
+int loggetfd(void);
+void logsetfd(int);
+int logreadfd(int);
+
unsigned int loggetopts(void);
void logsetopts(unsigned int);
#define LOGERR_DEBUG (1U << 6)
diff --git a/src/privsep-bpf.c b/src/privsep-bpf.c
index ddd3cd82..23da9a07 100644
--- a/src/privsep-bpf.c
+++ b/src/privsep-bpf.c
@@ -70,9 +70,21 @@ ps_bpf_recvbpf(void *arg)
* This mechanism allows us to read each packet from the buffer. */
while (!(bpf->bpf_flags & BPF_EOF)) {
len = bpf_read(bpf, buf, sizeof(buf));
- if (len == -1)
- logerr(__func__);
- if (len == -1 || len == 0)
+ if (len == -1) {
+ int error = errno;
+
+ logerr("%s: %s", psp->psp_ifname, __func__);
+ if (error != ENXIO)
+ break;
+ /* If the interface has departed, close the BPF
+ * socket. This stops log spam if RTM_IFANNOUNCE is
+ * delayed in announcing the departing interface. */
+ eloop_event_delete(psp->psp_ctx->eloop, bpf->bpf_fd);
+ bpf_close(bpf);
+ psp->psp_bpf = NULL;
+ break;
+ }
+ if (len == 0)
break;
psm.ps_flags = bpf->bpf_flags;
len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
@@ -107,6 +119,12 @@ ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
return -1;
}
+ /* We might have had an earlier ENXIO error. */
+ if (psp->psp_bpf == NULL) {
+ errno = ENXIO;
+ return -1;
+ }
+
return bpf_send(psp->psp_bpf, psp->psp_proto,
iov->iov_base, iov->iov_len);
}
diff --git a/src/privsep-linux.c b/src/privsep-linux.c
index 5d35ae2c..01f4975c 100644
--- a/src/privsep-linux.c
+++ b/src/privsep-linux.c
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -47,6 +48,14 @@
#include "logerr.h"
#include "privsep.h"
+/*
+ * Set this to debug SECCOMP.
+ * Then run dhcpcd with strace -f and strace will even translate
+ * the failing syscall into the __NR_name define we need to use below.
+ * DO NOT ENABLE THIS FOR PRODUCTION BUILDS!
+ */
+//#define SECCOMP_FILTER_DEBUG
+
static ssize_t
ps_root_dosendnetlink(int protocol, struct msghdr *msg)
{
@@ -125,7 +134,11 @@ ps_root_sendnetlink(struct dhcpcd_ctx *ctx, int protocol, struct msghdr *msg)
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
offsetof(struct seccomp_data, nr))
+#ifdef SECCOMP_FILTER_DEBUG
+#define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
+#else
#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
+#endif
/* I personally find this quite nutty.
* Why can a system header not define a default for this? */
@@ -247,6 +260,9 @@ static struct sock_filter ps_seccomp_filter[] = {
#ifdef __NR_munmap
SECCOMP_ALLOW(__NR_munmap),
#endif
+#ifdef __NR_nanosleep
+ SECCOMP_ALLOW(__NR_nanosleep), /* XXX should use ppoll instead */
+#endif
#ifdef __NR_ppoll
SECCOMP_ALLOW(__NR_ppoll),
#endif
@@ -259,6 +275,9 @@ static struct sock_filter ps_seccomp_filter[] = {
#ifdef __NR_readv
SECCOMP_ALLOW(__NR_readv),
#endif
+#ifdef __NR_recv
+ SECCOMP_ALLOW(__NR_recv),
+#endif
#ifdef __NR_recvfrom
SECCOMP_ALLOW(__NR_recvfrom),
#endif
@@ -268,6 +287,9 @@ static struct sock_filter ps_seccomp_filter[] = {
#ifdef __NR_rt_sigreturn
SECCOMP_ALLOW(__NR_rt_sigreturn),
#endif
+#ifdef __NR_send
+ SECCOMP_ALLOW(__NR_send),
+#endif
#ifdef __NR_sendmsg
SECCOMP_ALLOW(__NR_sendmsg),
#endif
@@ -277,9 +299,15 @@ static struct sock_filter ps_seccomp_filter[] = {
#ifdef __NR_shutdown
SECCOMP_ALLOW(__NR_shutdown),
#endif
+#ifdef __NR_time
+ SECCOMP_ALLOW(__NR_time),
+#endif
#ifdef __NR_wait4
SECCOMP_ALLOW(__NR_wait4),
#endif
+#ifdef __NR_waitpid
+ SECCOMP_ALLOW(__NR_waitpid),
+#endif
#ifdef __NR_write
SECCOMP_ALLOW(__NR_write),
#endif
@@ -299,10 +327,44 @@ static struct sock_fprog ps_seccomp_prog = {
.filter = ps_seccomp_filter,
};
+#ifdef SECCOMP_FILTER_DEBUG
+static void
+ps_seccomp_violation(__unused int signum, siginfo_t *si, __unused void *context)
+{
+
+ logerrx("%s: unexpected syscall %d (arch=0x%x)",
+ __func__, si->si_syscall, si->si_arch);
+ _exit(EXIT_FAILURE);
+}
+
+static int
+ps_seccomp_debug(void)
+{
+ struct sigaction sa = {
+ .sa_flags = SA_SIGINFO,
+ .sa_sigaction = &ps_seccomp_violation,
+ };
+ sigset_t mask;
+
+ /* Install a signal handler to catch any issues with our filter. */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGSYS);
+ if (sigaction(SIGSYS, &sa, NULL) == -1 ||
+ sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
+ return -1;
+
+ return 0;
+}
+#endif
+
int
ps_seccomp_enter(void)
{
+#ifdef SECCOMP_FILTER_DEBUG
+ ps_seccomp_debug();
+#endif
+
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 ||
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &ps_seccomp_prog) == -1)
{
diff --git a/src/privsep-root.c b/src/privsep-root.c
index 770dd953..afe9c8f6 100644
--- a/src/privsep-root.c
+++ b/src/privsep-root.c
@@ -561,6 +561,10 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
rlen = sizeof(mtime);
}
break;
+ case PS_LOGREOPEN:
+ logclose();
+ err = logopen(ctx->logfile);
+ break;
#ifdef AUTH
case PS_AUTH_MONORDM:
err = ps_root_monordm(data, len);
@@ -780,18 +784,34 @@ ps_root_dispatch(void *arg)
logerr(__func__);
}
+static void
+ps_root_log(void *arg)
+{
+ struct dhcpcd_ctx *ctx = arg;
+
+ if (logreadfd(ctx->ps_log_fd) == -1)
+ logerr(__func__);
+}
+
pid_t
ps_root_start(struct dhcpcd_ctx *ctx)
{
- int fd[2];
+ int logfd[2], datafd[2];
pid_t pid;
- if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1)
+ if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, logfd) == -1)
return -1;
- if (ps_setbuf_fdpair(fd) == -1)
+#ifdef PRIVSEP_RIGHTS
+ if (ps_rights_limit_fdpair(logfd) == -1)
+ return -1;
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, datafd) == -1)
+ return -1;
+ if (ps_setbuf_fdpair(datafd) == -1)
return -1;
#ifdef PRIVSEP_RIGHTS
- if (ps_rights_limit_fdpair(fd) == -1)
+ if (ps_rights_limit_fdpair(datafd) == -1)
return -1;
#endif
@@ -800,14 +820,22 @@ ps_root_start(struct dhcpcd_ctx *ctx)
ps_root_startcb, ps_root_signalcb, 0);
if (pid == 0) {
- ctx->ps_data_fd = fd[1];
- close(fd[0]);
+ ctx->ps_log_fd = logfd[1];
+ if (eloop_event_add(ctx->eloop, ctx->ps_log_fd,
+ ps_root_log, ctx) == -1)
+ return -1;
+ close(logfd[0]);
+ ctx->ps_data_fd = datafd[1];
+ close(datafd[0]);
return 0;
} else if (pid == -1)
return -1;
- ctx->ps_data_fd = fd[0];
- close(fd[1]);
+ logsetfd(logfd[0]);
+ close(logfd[1]);
+
+ ctx->ps_data_fd = datafd[0];
+ close(datafd[1]);
if (eloop_event_add(ctx->eloop, ctx->ps_data_fd,
ps_root_dispatch, ctx) == -1)
return -1;
@@ -906,6 +934,15 @@ ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
return ps_root_readerror(ctx, time, sizeof(*time));
}
+ssize_t
+ps_root_logreopen(struct dhcpcd_ctx *ctx)
+{
+
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_LOGREOPEN, 0, NULL, 0) == -1)
+ return -1;
+ return ps_root_readerror(ctx, NULL, 0);
+}
+
#ifdef PRIVSEP_GETIFADDRS
int
ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
diff --git a/src/privsep-root.h b/src/privsep-root.h
index 146622b1..9d8a1597 100644
--- a/src/privsep-root.h
+++ b/src/privsep-root.h
@@ -47,6 +47,7 @@ ssize_t ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
const void *, size_t);
+ssize_t ps_root_logreopen(struct dhcpcd_ctx *);
ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *);
#ifdef PRIVSEP_GETIFADDRS
diff --git a/src/privsep-sun.c b/src/privsep-sun.c
index f406f4ee..2c5d586a 100644
--- a/src/privsep-sun.c
+++ b/src/privsep-sun.c
@@ -37,6 +37,8 @@
#warning Solaris privsep should compile but wont work,
#warning no DLPI support, ioctl support need rework
+/* We should implement privileges(5) as well.
+ * https://illumos.org/man/5/privileges */
static ssize_t
ps_root_doioctl6(unsigned long req, void *data, size_t len)
diff --git a/src/privsep.c b/src/privsep.c
index e9fa463f..6e76902a 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -542,6 +542,19 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge)
dropped = ps_dropprivs(ctx);
if (forked)
ctx->options |= DHCPCD_FORKED;
+
+ /*
+ * If we don't have a root process, we cannot use syslog.
+ * If it cannot be opened before chrooting then syslog(3) will fail.
+ * openlog(3) does not return an error which doubly sucks.
+ */
+ if (ctx->ps_root_fd == -1) {
+ unsigned int logopts = loggetopts();
+
+ logopts &= ~LOGERR_LOG;
+ logsetopts(logopts);
+ }
+
if (dropped == -1) {
logerr("%s: ps_dropprivs", __func__);
return -1;
diff --git a/src/privsep.h b/src/privsep.h
index 4fd33e7f..87c84eb9 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -52,6 +52,7 @@
#define PS_AUTH_MONORDM 0x0017
#define PS_CTL 0x0018
#define PS_CTL_EOF 0x0019
+#define PS_LOGREOPEN 0x0020
/* BSD Commands */
#define PS_IOCTLLINK 0x0101
Archive administrator: postmaster@marples.name