changeset 5331:d075e31eb148 draft

privsep: For Linux and Solaris, set RLIMIT_NOFILES to nevents Because poll(2) returns EINVAL if nfds is higher. This really blows chunks, but it is what it is. An attacker could close a fd and open something else, but it's the best we can do.
author Roy Marples <roy@marples.name>
date Tue, 09 Jun 2020 22:39:05 +0100
parents 7b6f2daea002
children b22045bba8b9
files src/dhcpcd.c src/eloop.c src/eloop.h src/privsep-control.c src/privsep-control.h src/privsep-root.h src/privsep.c src/privsep.h
diffstat 8 files changed, 68 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcpcd.c	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/dhcpcd.c	Tue Jun 09 22:39:05 2020 +0100
@@ -2321,6 +2321,10 @@
 	if (dhcp_vendor(ctx.vendor, sizeof(ctx.vendor)) == -1)
 		logerrx("dhcp_vendor");
 
+	/* Start handling kernel messages for interfaces, addresses and
+	 * routes. */
+	eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx);
+
 #ifdef PRIVSEP
 	if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
 		goto exit_failure;
@@ -2331,10 +2335,6 @@
 	if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND))
 		ctx.options |= DHCPCD_WAITIP;
 
-	/* Start handling kernel messages for interfaces, addresses and
-	 * routes. */
-	eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx);
-
 	ctx.ifaces = if_discover(&ctx, &ifaddrs, ctx.ifc, ctx.ifv);
 	if (ctx.ifaces == NULL) {
 		logerr("%s: if_discover", __func__);
--- a/src/eloop.c	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/eloop.c	Tue Jun 09 22:39:05 2020 +0100
@@ -297,6 +297,13 @@
 	}
 }
 
+size_t
+eloop_event_count(const struct eloop *eloop)
+{
+
+	return eloop->nevents;
+}
+
 int
 eloop_event_add_rw(struct eloop *eloop, int fd,
     void (*read_cb)(void *), void *read_cb_arg,
--- a/src/eloop.h	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/eloop.h	Tue Jun 09 22:39:05 2020 +0100
@@ -54,6 +54,7 @@
 
 unsigned long long eloop_timespec_diff(const struct timespec *tsp,
     const struct timespec *usp, unsigned int *nsp);
+size_t eloop_event_count(const struct eloop  *);
 int eloop_event_add_rw(struct eloop *, int,
     void (*)(void *), void *,
     void (*)(void *), void *);
--- a/src/privsep-control.c	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/privsep-control.c	Tue Jun 09 22:39:05 2020 +0100
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/resource.h>
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,34 +36,6 @@
 #include "logerr.h"
 #include "privsep.h"
 
-int
-ps_ctl_limitresources(struct dhcpcd_ctx *ctx)
-{
-	struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
-
-	if (ctx->ps_control_pid != getpid()) {
-		/* Prohibit new files, sockets, etc */
-		if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) {
-			logerr("setrlimit RLIMIT_NOFILE");
-			return -1;
-		}
-	}
-
-	/* Prohibit large files */
-	if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) {
-		logerr("setrlimit RLIMIT_FSIZE");
-		return -1;
-	}
-
-	/* Prohibit forks */
-	if (setrlimit(RLIMIT_NPROC, &rzero) == -1) {
-		logerr("setrlimit RLIMIT_NPROC");
-		return -1;
-	}
-
-	return 0;
-}
-
 static int
 ps_ctl_startcb(void *arg)
 {
--- a/src/privsep-control.h	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/privsep-control.h	Tue Jun 09 22:39:05 2020 +0100
@@ -32,7 +32,6 @@
 #define IN_PRIVSEP_CONTROLLER(ctx) \
     (IN_PRIVSEP((ctx)) && (ctx)->ps_control_pid == getpid())
 
-int ps_ctl_limitresources(struct dhcpcd_ctx *);
 pid_t ps_ctl_start(struct dhcpcd_ctx *);
 int ps_ctl_stop(struct dhcpcd_ctx *);
 ssize_t ps_ctl_handleargs(struct fd_list *, char *, size_t);
--- a/src/privsep-root.h	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/privsep-root.h	Tue Jun 09 22:39:05 2020 +0100
@@ -64,7 +64,6 @@
 #endif
 #ifdef __linux__
 ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
-ssize_t ps_root_writepathuint(struct dhcpcd_ctx *, const char *, unsigned int);
 #endif
 
 #ifdef PLUGIN_DEV
--- a/src/privsep.c	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/privsep.c	Tue Jun 09 22:39:05 2020 +0100
@@ -39,6 +39,7 @@
  * this in a script or something.
  */
 
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -128,11 +129,57 @@
 		return -1;
 	}
 
-#ifdef PRIVSEP_CONTROLLER
-	if (ps_ctl_limitresources(ctx) == -1)
+	struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
+
+#if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
+	/* These sandbox technologies do not work well with
+	 * resource limits. */
+#else
+	if (ctx->ps_control_pid != getpid()) {
+		/* Prohibit new files, sockets, etc */
+#if defined(__linux__) || defined(__sun)
+		/*
+		 * If poll(2) is called with nfds > RLIMIT_NOFILE
+		 * then it returns EINVAL.
+		 * This blows.
+		 * Do the best we can and limit to what we need.
+		 * An attacker could potentially close a file and
+		 * open a new one still, but that cannot be helped.
+		 */
+		unsigned long maxfd;
+		maxfd = (unsigned long)eloop_event_count(ctx->eloop);
+		if (IN_PRIVSEP_SE(ctx))
+			maxfd++; /* XXX why? */
+
+		struct rlimit rmaxfd = {
+		    .rlim_cur = (unsigned long)maxfd,
+		    .rlim_max = (unsigned long)maxfd
+		};
+		if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1) {
+			logerr("setrlimit RLIMIT_NOFILE");
+			return -1;
+		}
+#else
+		if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) {
+			logerr("setrlimit RLIMIT_NOFILE");
+			return -1;
+		}
+#endif
+	}
+
+	/* Prohibit large files */
+	if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) {
+		logerr("setrlimit RLIMIT_FSIZE");
 		return -1;
-#elif !defined(HAVE_CAPSIUM) && !defined(HAVE_PLEDGE)
-#warning No sandbox support
+	}
+
+#ifdef RLIMIT_NPROC
+	/* Prohibit forks */
+	if (setrlimit(RLIMIT_NPROC, &rzero) == -1) {
+		logerr("setrlimit RLIMIT_NPROC");
+		return -1;
+	}
+#endif
 #endif
 
 	return 0;
--- a/src/privsep.h	Tue Jun 09 20:36:22 2020 +0100
+++ b/src/privsep.h	Tue Jun 09 22:39:05 2020 +0100
@@ -62,9 +62,9 @@
 #define	PS_IFIGNOREGRP		0x0106
 
 /* Dev Commands */
-#define	PS_DEV_LISTENING	0x0201
-#define	PS_DEV_INITTED		0x0202
-#define	PS_DEV_IFCMD		0x0203
+#define	PS_DEV_LISTENING	0x1001
+#define	PS_DEV_INITTED		0x1002
+#define	PS_DEV_IFCMD		0x1003
 
 /* Dev Interface Commands (via flags) */
 #define	PS_DEV_IFADDED		0x0001
@@ -72,8 +72,8 @@
 #define	PS_DEV_IFUPDATED	0x0003
 
 /* Control Type (via flags) */
-#define	PS_CTL_PRIV		0x0301
-#define	PS_CTL_UNPRIV		0x0302
+#define	PS_CTL_PRIV		0x0004
+#define	PS_CTL_UNPRIV		0x0005
 
 /* Process commands */
 #define	PS_START		0x4000