summaryrefslogtreecommitdiffstats
path: root/src/privsep.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-06-05 20:24:21 +0100
committerRoy Marples <roy@marples.name>2020-06-05 20:24:21 +0100
commit7ef3d6a703f5c3b1fa537ae324f7d79f085f31f9 (patch)
tree096d27b660b63c09ff2d66c183ab3a21b1fbea6f /src/privsep.c
parentff6831723b04b617f73e88cf84387f46eea1faf5 (diff)
downloaddhcpcd-7ef3d6a703f5c3b1fa537ae324f7d79f085f31f9.tar.xz
privsep: Limit rights generically rather than Capsicum specifc
You never know when another sandbox tech comes around. While here, add limits for every socket in the unpriviledged processes. Some were absent before. Also, note that RLIMIT_NOFILE breaks our control socket so temporary disable that.
Diffstat (limited to 'src/privsep.c')
-rw-r--r--src/privsep.c146
1 files changed, 118 insertions, 28 deletions
diff --git a/src/privsep.c b/src/privsep.c
index 271c0c39..3b836893 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -113,9 +113,6 @@ int
ps_dropprivs(struct dhcpcd_ctx *ctx)
{
struct passwd *pw = ctx->ps_user;
-#if !defined(HAVE_PLEDGE)
- struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
-#endif
if (!(ctx->options & DHCPCD_FORKED))
logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name);
@@ -132,9 +129,14 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
return -1;
}
-#if defined(HAVE_PLEDGE)
- /* None of these resource limits work with pledge. */
+#if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
+ /* Resource limits are not needed for these sandboxes */
#else
+ struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
+
+ /* We can't use RLIMIT_NOFILE because that breaks our control socket.
+ * XXX Offload to a new process? */
+#if 0
#ifndef __linux__ /* breaks ppoll */
/* Prohibit new files, sockets, etc */
if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) {
@@ -142,14 +144,13 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
return -1;
}
#endif
+#endif
-#ifndef HAVE_CAPSICUM /* breaks sending over our IPC */
/* Prohibit large files */
if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) {
logerr("setrlimit RLIMIT_FSIZE");
return -1;
}
-#endif
#ifdef RLIMIT_NPROC
/* Prohibit forks */
@@ -198,6 +199,71 @@ ps_setbuf(int fd)
return 0;
}
+int
+ps_setbuf_fdpair(int fd[])
+{
+
+ if (ps_setbuf(fd[0]) == -1 || ps_setbuf(fd[1]) == -1)
+ return -1;
+ return 0;
+}
+
+#ifdef PRIVSEP_RIGHTS
+int
+ps_rights_limit_ioctl(int fd)
+{
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_IOCTL);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS)
+ return -1;
+ return 0;
+}
+
+int
+ps_rights_limit_fd_fctnl(int fd)
+{
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT,
+ CAP_ACCEPT, CAP_FCNTL);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS)
+ return -1;
+ return 0;
+}
+
+int
+ps_rights_limit_fd(int fd)
+{
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS)
+ return -1;
+ return 0;
+}
+
+int
+ps_rights_limit_fd_rdonly(int fd)
+{
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_READ, CAP_EVENT);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS)
+ return -1;
+ return 0;
+}
+
+int
+ps_rights_limit_fdpair(int fd[])
+{
+
+ if (ps_rights_limit_fd(fd[0]) == -1 || ps_rights_limit_fd(fd[1]) == -1)
+ return -1;
+ return 0;
+}
+#endif
+
pid_t
ps_dostart(struct dhcpcd_ctx *ctx,
pid_t *priv_pid, int *priv_fd,
@@ -208,17 +274,22 @@ ps_dostart(struct dhcpcd_ctx *ctx,
int stype;
int fd[2];
pid_t pid;
-#ifdef HAVE_CAPSICUM
- cap_rights_t rights;
-
- cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN);
-#endif
stype = SOCK_CLOEXEC | SOCK_NONBLOCK;
if (socketpair(AF_UNIX, SOCK_DGRAM | stype, 0, fd) == -1) {
- logerr("socketpair");
+ logerr("%s: socketpair", __func__);
return -1;
}
+ if (ps_setbuf_fdpair(fd) == -1) {
+ logerr("%s: ps_setbuf_fdpair", __func__);
+ return -1;
+ }
+#ifdef PRIVSEP_RIGHTS
+ if (ps_rights_limit_fdpair(fd) == -1) {
+ logerr("%s: ps_rights_limit_fdpair", __func__);
+ return -1;
+ }
+#endif
switch (pid = fork()) {
case -1:
@@ -227,23 +298,13 @@ ps_dostart(struct dhcpcd_ctx *ctx,
case 0:
*priv_fd = fd[1];
close(fd[0]);
- ps_setbuf(*priv_fd);
break;
default:
*priv_pid = pid;
*priv_fd = fd[0];
close(fd[1]);
- ps_setbuf(*priv_fd);
if (recv_unpriv_msg == NULL)
;
-#ifdef HAVE_CAPSICUM
- else if (cap_rights_limit(*priv_fd, &rights) == -1
- && errno != ENOSYS)
- {
- logerr("%s: cap_rights_limit", __func__);
- return -1;
- }
-#endif
else if (eloop_event_add(ctx->eloop, *priv_fd,
recv_unpriv_msg, recv_ctx) == -1)
{
@@ -284,11 +345,6 @@ ps_dostart(struct dhcpcd_ctx *ctx,
goto errexit;
}
-#ifdef HAVE_CAPSICUM
- if (cap_rights_limit(*priv_fd, &rights) == -1 && errno != ENOSYS)
- goto errexit;
-#endif
-
if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1)
{
logerr("%s: eloop_event_add", __func__);
@@ -392,6 +448,40 @@ started:
}
int
+ps_mastersandbox(struct dhcpcd_ctx *ctx)
+{
+
+ if (ps_dropprivs(ctx) == -1) {
+ logerr("%s: ps_dropprivs", __func__);
+ return -1;
+ }
+
+#ifdef PRIVSEP_RIGHTS
+ if ((ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1 ||
+ ps_rights_limit_fd(ctx->link_fd) == -1) &&
+ errno != ENOSYS)
+ {
+ logerr("%s: cap_rights_limit", __func__);
+ return -1;
+ }
+#endif
+#ifdef HAVE_CAPSICUM
+ if (cap_enter() == -1 && errno != ENOSYS) {
+ logerr("%s: cap_enter", __func__);
+ return -1;
+ }
+#endif
+#ifdef HAVE_PLEDGE
+ if (pledge("stdio route", NULL) == -1) {
+ logerr("%s: pledge", __func__);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+int
ps_stop(struct dhcpcd_ctx *ctx)
{
int r, ret = 0;