summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-06-09 22:39:05 +0100
committerRoy Marples <roy@marples.name>2020-06-09 22:39:05 +0100
commitd196c8b662de184e1e79600b16eb53498517ea1f (patch)
tree37ec3cade59bf03e850606123b3e5cbfd343a7d3
parent6b6a7cb1d0700ca404f58854e477aa00d64e97f9 (diff)
downloaddhcpcd-d196c8b662de184e1e79600b16eb53498517ea1f.tar.xz
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.
-rw-r--r--src/dhcpcd.c8
-rw-r--r--src/eloop.c7
-rw-r--r--src/eloop.h1
-rw-r--r--src/privsep-control.c30
-rw-r--r--src/privsep-control.h1
-rw-r--r--src/privsep-root.h1
-rw-r--r--src/privsep.c55
-rw-r--r--src/privsep.h10
8 files changed, 68 insertions, 45 deletions
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index 234761c6..0ccfe8ac 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -2321,6 +2321,10 @@ printpidfile:
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 @@ printpidfile:
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__);
diff --git a/src/eloop.c b/src/eloop.c
index ae63241e..6579a20c 100644
--- a/src/eloop.c
+++ b/src/eloop.c
@@ -297,6 +297,13 @@ eloop_event_setup_fds(struct eloop *eloop)
}
}
+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,
diff --git a/src/eloop.h b/src/eloop.h
index 9001c1b7..c7d81e34 100644
--- a/src/eloop.h
+++ b/src/eloop.h
@@ -54,6 +54,7 @@ struct eloop;
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 *);
diff --git a/src/privsep-control.c b/src/privsep-control.c
index 114603a9..bd74198e 100644
--- a/src/privsep-control.c
+++ b/src/privsep-control.c
@@ -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)
{
diff --git a/src/privsep-control.h b/src/privsep-control.h
index 7f0e473a..3d9522ad 100644
--- a/src/privsep-control.h
+++ b/src/privsep-control.h
@@ -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);
diff --git a/src/privsep-root.h b/src/privsep-root.h
index 1de284bf..5d6e1248 100644
--- a/src/privsep-root.h
+++ b/src/privsep-root.h
@@ -64,7 +64,6 @@ ssize_t ps_root_ifignoregroup(struct dhcpcd_ctx *, const char *);
#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
diff --git a/src/privsep.c b/src/privsep.c
index a4b03fde..c93f00b0 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -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 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
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;
+ }
+
+#ifdef RLIMIT_NPROC
+ /* Prohibit forks */
+ if (setrlimit(RLIMIT_NPROC, &rzero) == -1) {
+ logerr("setrlimit RLIMIT_NPROC");
return -1;
-#elif !defined(HAVE_CAPSIUM) && !defined(HAVE_PLEDGE)
-#warning No sandbox support
+ }
+#endif
#endif
return 0;
diff --git a/src/privsep.h b/src/privsep.h
index 7428adc7..2bc9bac3 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -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