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@marples.name .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 #include #include +#include #include #include @@ -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