Hi tech@

This is a revised version of pledging dhcpd(8) with earler pledging.

Hoist up sync_init() due to a multicast setsockopt(2) (IP_MULTICAST_TTL) that
pledge doesn't allow, also hoist up the daemon(3) section, getpwnam(3) and the
check if arguments -A, -C or -L were used (pf table handling) since it calls
2 ioctl(2)'s that pledge pf doesn't allow.

After this if !udpsockmode then apply the following annotations:

"rpath":
        icmp_startup()->getprotobyname(3)->read /etc/protocols
"inet":
        icmp_startup()->socket(2)
"sendfd":
        for sendmsg(2) in ICMP echo request
"proc/id"
        chroot(2) and privdrop section
        
If in udpsockmode then the pledge needs to happen inside udpsock_startup()
instead of main() since setsockopt(2) IP_RECVIF is not allowed by pledge. After
that happens then apply the same pledge with the annotations above, although
additionally this code path also needs "route" for ioctl(2) SIOCGIFADDR.

Just before the main loop of the program then it can drop to "stdio inet route
sendfd" if in udpsockmode or else just to "stdio inet sendfd".

Any comments with this implementation? Specifically for the UDP code path since
I don't have at the moment a way to test DHCPINFORM requests on non Ethernet 
packets?

Index: dhcpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/dhcpd.c,v
retrieving revision 1.48
diff -u -p -u -r1.48 dhcpd.c
--- dhcpd.c     10 Feb 2015 23:06:13 -0000      1.48
+++ dhcpd.c     2 Dec 2015 11:28:50 -0000
@@ -45,7 +45,7 @@
 #include <err.h>
 #include <pwd.h>
 
-void usage(void);
+__dead void usage(void);
 
 time_t cur_time, last_scan;
 struct group root_group;
@@ -187,22 +187,18 @@ main(int argc, char *argv[])
                if (setrtable(rdomain) == -1)
                        error("setrtable (%m)");
 
-       if (udpsockmode)
-               udpsock_startup(udpaddr);
-       icmp_startup(1, lease_pinged);
-
        if (syncsend || syncrecv) {
                syncfd = sync_init(sync_iface, sync_baddr, sync_port);
                if (syncfd == -1)
                        err(1, "sync init");
        }
 
-       if ((pw = getpwnam("_dhcp")) == NULL)
-               error("user \"_dhcp\" not found");
-
        if (daemonize)
                daemon(0, 0);
 
+       if ((pw = getpwnam("_dhcp")) == NULL)
+               error("user \"_dhcp\" not found");
+
        /* don't go near /dev/pf unless we actually intend to use it */
        if ((abandoned_tab != NULL) ||
            (changedmac_tab != NULL) ||
@@ -227,6 +223,15 @@ main(int argc, char *argv[])
                }
        }
 
+       if (udpsockmode) {
+               udpsock_startup(udpaddr);
+       } else {
+               if (pledge("stdio rpath inet sendfd proc id", NULL) == -1)
+                       err(1, "pledge");
+       }
+
+       icmp_startup(1, lease_pinged);
+
        if (chroot(_PATH_VAREMPTY) == -1)
                error("chroot %s: %m", _PATH_VAREMPTY);
        if (chdir("/") == -1)
@@ -236,6 +241,14 @@ main(int argc, char *argv[])
            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                error("can't drop privileges: %m");
 
+       if (udpsockmode) {
+               if (pledge("stdio inet route sendfd", NULL) == -1)
+                       err(1, "pledge");
+       } else {
+               if (pledge("stdio inet sendfd", NULL) == -1)
+                       err(1, "pledge");
+       }
+
        add_timeout(cur_time + 5, periodic_scan, NULL);
        dispatch();
 
@@ -243,7 +256,7 @@ main(int argc, char *argv[])
        exit(0);
 }
 
-void
+__dead void
 usage(void)
 {
        extern char *__progname;
Index: udpsock.c
===================================================================
RCS file: /cvs/src/usr.sbin/dhcpd/udpsock.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 udpsock.c
--- udpsock.c   16 Jan 2015 06:40:16 -0000      1.2
+++ udpsock.c   2 Dec 2015 11:28:55 -0000
@@ -56,6 +56,9 @@ udpsock_startup(struct in_addr bindaddr)
                error("setsocketopt IP_RECVIF failed for udp: %s",
                    strerror(errno));
 
+       if (pledge("stdio rpath inet route sendfd proc id", NULL) == -1)
+               error("pledge: %s", strerror(errno));
+
        sin4.sin_family = AF_INET;
        sin4.sin_len = sizeof(sin4);
        sin4.sin_addr = bindaddr;

Reply via email to