]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Only set RLIMIT_NOFILES for supported platforms
authorRoy Marples <roy@marples.name>
Fri, 12 Nov 2021 14:24:11 +0000 (14:24 +0000)
committerRoy Marples <roy@marples.name>
Fri, 12 Nov 2021 14:24:11 +0000 (14:24 +0000)
Basically only for NetBSD, DragonFlyBSD, kqueue or epoll platforms.
All others will use poll(2) and return EINVAL if nfds > RLIMIT_NOFILES.

Trying to work out our nfs limit relies on already listening to
all FD's which may not be the case and was problematic.
Luckily all platforms aside from Solaris have new file creation
sandboxed away aside from accept(2) so this should still be safe.

src/privsep.c

index 8b8e159a3637ca6b071624ddc15689172c7a6ce9..f08b4028c561db35270cae145a077e40274e4cc7 100644 (file)
@@ -145,35 +145,27 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
 
        struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
 
+       /* Prohibit new files, sockets, etc */
+       /*
+        * If poll(2) is called with nfds>RLIMIT_NOFILE then it returns EINVAL.
+        * We don't know the final value of nfds at this point *easily*.
+        * Sadly, this is a POSIX limitation and most platforms adhere to it.
+        * However, some are not that strict and are whitelisted below.
+        * Also, if we're not using poll then we can be restrictive.
+        *
+        * For the non whitelisted platforms there should be a sandbox to
+        * fallback to where we don't allow new files, etc:
+        *      Linux:seccomp, FreeBSD:capsicum, OpenBSD:pledge
+        * Solaris users are sadly out of luck on both counts.
+        */
+#if defined(__NetBSD__) || defined(__DragonFly__) || \
+    defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+       /* The control proxy *does* need to create new fd's via accept(2). */
        if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) {
-               /* Prohibit new files, sockets, etc */
-#if (defined(__linux__) || defined(__sun) || defined(__OpenBSD__)) && \
-    !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
-               /*
-                * 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++; /* why? */
-
-               struct rlimit rmaxfd = {
-                   .rlim_cur = maxfd,
-                   .rlim_max = maxfd
-               };
-
-               if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1)
-                       logerr("setrlimit RLIMIT_NOFILE");
-#else
                if (setrlimit(RLIMIT_NOFILE, &rzero) == -1)
                        logerr("setrlimit RLIMIT_NOFILE");
-#endif
        }
+#endif
 
 #define DHC_NOCHKIO    (DHCPCD_STARTED | DHCPCD_DAEMONISE)
        /* Prohibit writing to files.