summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-09-20 19:09:08 +0100
committerRoy Marples <roy@marples.name>2020-09-20 19:09:08 +0100
commit8b204c618386a2d8fe4a44514824da6f6a462985 (patch)
tree23403481bf3b3fe6c76f7761928c0d9b22d3b6be
parent744f8864f72e008957da13f243e2321377bdba64 (diff)
downloaddhcpcd-8b204c618386a2d8fe4a44514824da6f6a462985.tar.xz
privsep: sandbox the launcher process
-rw-r--r--src/dhcpcd.c44
-rw-r--r--src/dhcpcd.h1
-rw-r--r--src/privsep.c20
-rw-r--r--src/privsep.h2
4 files changed, 41 insertions, 26 deletions
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index 8fbb6212..83161471 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -1417,16 +1417,7 @@ dhcpcd_signal_cb(int sig, void *arg)
}
if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) {
- if (sig == SIGHUP)
- return;
-
- pid_t pid = pidfile_read(ctx->pidfile);
- if (pid == -1) {
- if (errno != ENOENT)
- logerr("%s: pidfile_read",__func__);
- } else if (pid == 0)
- logerr("%s: pid cannot be zero", __func__);
- else if (kill(pid, sig) == -1)
+ if (sig != SIGHUP && kill(ctx->fork_pid, sig) == -1)
logerr("%s: kill", __func__);
return;
}
@@ -1769,9 +1760,16 @@ dhcpcd_fork_cb(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
int exit_code;
+ bool do_exit;
ssize_t len;
- len = read(ctx->fork_fd, &exit_code, sizeof(exit_code));
+ if (ctx->fork_pid == 0) {
+ do_exit = false;
+ len = read(ctx->fork_fd, &ctx->fork_pid, sizeof(ctx->fork_pid));
+ } else {
+ do_exit = true;
+ len = read(ctx->fork_fd, &exit_code, sizeof(exit_code));
+ }
if (len == -1) {
logerr(__func__);
exit_code = EXIT_FAILURE;
@@ -1780,7 +1778,8 @@ dhcpcd_fork_cb(void *arg)
__func__, len, sizeof(exit_code));
exit_code = EXIT_FAILURE;
}
- eloop_exit(ctx->eloop, exit_code);
+ if (do_exit)
+ eloop_exit(ctx->eloop, exit_code);
}
static void
@@ -2156,7 +2155,7 @@ printpidfile:
{
ctx.options |= DHCPCD_FORKED; /* pretend child process */
#ifdef PRIVSEP
- if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
+ if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1)
goto exit_failure;
#endif
ifp = calloc(1, sizeof(*ifp));
@@ -2208,12 +2207,9 @@ printpidfile:
ctx.options & DHCPCD_DUMPLEASE);
if (ctx.control_fd != -1) {
#ifdef PRIVSEP
- ctx.options &= ~DHCPCD_FORKED;
- if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) {
- ctx.options |= DHCPCD_FORKED;
+ if (IN_PRIVSEP(&ctx) &&
+ ps_mastersandbox(&ctx, NULL) == -1)
goto exit_failure;
- }
- ctx.options |= DHCPCD_FORKED;
#endif
if (!(ctx.options & DHCPCD_DUMPLEASE))
loginfox("sending commands to dhcpcd process");
@@ -2316,6 +2312,9 @@ printpidfile:
logerr("fork");
goto exit_failure;
case 0:
+ /* Inform the launcher of our pid as it's chrooted */
+ pid = getpid();
+ write(ctx.fork_fd, &pid, sizeof(pid));
break;
default:
ctx.options |= DHCPCD_FORKED; /* A lie */
@@ -2324,8 +2323,8 @@ printpidfile:
}
break;
default:
- ctx.options |= DHCPCD_FORKED; /* A lie */
setproctitle("[launcher]");
+ ctx.options |= DHCPCD_FORKED; /* A lie */
ctx.fork_fd = fork_fd[0];
close(fork_fd[1]);
#ifdef PRIVSEP_RIGHTS
@@ -2351,6 +2350,11 @@ printpidfile:
eloop_event_add(ctx.eloop, ctx.stderr_fd,
dhcpcd_stderr_cb, &ctx);
}
+#ifdef PRIVSEP
+ if (IN_PRIVSEP(&ctx) &&
+ ps_mastersandbox(&ctx, "stdio proc") == -1)
+ goto exit_failure;
+#endif
goto run_loop;
}
@@ -2428,7 +2432,7 @@ printpidfile:
eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx);
#ifdef PRIVSEP
- if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
+ if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1)
goto exit_failure;
#endif
diff --git a/src/dhcpcd.h b/src/dhcpcd.h
index 03449e58..a3a54b06 100644
--- a/src/dhcpcd.h
+++ b/src/dhcpcd.h
@@ -122,6 +122,7 @@ struct dhcpcd_ctx {
bool stderr_valid;
int stderr_fd; /* FD for logging to stderr */
int fork_fd; /* FD for the fork init signal pipe */
+ pid_t fork_pid;
const char *cffile;
unsigned long long options;
char *logfile;
diff --git a/src/privsep.c b/src/privsep.c
index ffaa303a..2c161e15 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -118,7 +118,8 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
if (!(ctx->options & DHCPCD_FORKED))
logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name);
- if (chroot(pw->pw_dir) == -1)
+ if (chroot(pw->pw_dir) == -1 &&
+ (errno != EPERM || ctx->options & DHCPCD_FORKED))
logerr("%s: chroot `%s'", __func__, pw->pw_dir);
if (chdir("/") == -1)
logerr("%s: chdir `/'", __func__);
@@ -517,11 +518,18 @@ ps_entersandbox(const char *_pledge, const char **sandbox)
}
int
-ps_mastersandbox(struct dhcpcd_ctx *ctx)
+ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge)
{
const char *sandbox = NULL;
-
- if (ps_dropprivs(ctx) == -1) {
+ bool forked;
+ int dropped;
+
+ forked = ctx->options & DHCPCD_FORKED;
+ ctx->options &= ~DHCPCD_FORKED;
+ dropped = ps_dropprivs(ctx);
+ if (forked)
+ ctx->options |= DHCPCD_FORKED;
+ if (dropped == -1) {
logerr("%s: ps_dropprivs", __func__);
return -1;
}
@@ -537,7 +545,9 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx)
}
#endif
- if (ps_entersandbox("stdio route", &sandbox) == -1) {
+ if (_pledge == NULL)
+ _pledge = "stdio";
+ if (ps_entersandbox(_pledge, &sandbox) == -1) {
if (errno == ENOSYS) {
if (sandbox != NULL)
logwarnx("sandbox unavailable: %s", sandbox);
diff --git a/src/privsep.h b/src/privsep.h
index 260c3fda..93f7965e 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -175,7 +175,7 @@ int ps_init(struct dhcpcd_ctx *);
int ps_start(struct dhcpcd_ctx *);
int ps_stop(struct dhcpcd_ctx *);
int ps_entersandbox(const char *, const char **);
-int ps_mastersandbox(struct dhcpcd_ctx *);
+int ps_mastersandbox(struct dhcpcd_ctx *, const char *);
int ps_unrollmsg(struct msghdr *, struct ps_msghdr *, const void *, size_t);
ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,