So one of the big goals of dhcpcd was to implement Privilege Separation. This was achieved in dhcpcd-9 which was important because it was a required step of work to merge dhcpcd into FreeBSD base system. Once done, we can then look at what is required to enable Capsicum support, which is the last required step before dhcpcd can even be considered for importing into FreeBSD base system.

The good news is that basic Capsicum support has been enabled in this commit by ensuring all the file descriptors of the network facing processes are limited in their capability. The bad news is that capability mode is only enabled for the BPF processes- the end goal is that the master process is at least placed in capability mode.

So what’s the problem? Well, the first problem is that Capsicum is really hard to use, a lot of this is not helped by the documentation. It took a long time to work out how it works and how to use it. The second problem is that capability mode is really hard core- it stops a lot of stuff working dead in it’s tracks by killing access not capability limited in the global namespace.

From dhcpcds perspective the big issue is that

gethostname(3) and getifaddrs(3) won't work. This is the biggest show stopper, hard to IPC.

EDIT: gethostname(3) does work in Capsicum capabilities mode.

Let’s just take a moment to talk about getifaddrs(3)- it’s a really powerful interface to work out what interfaces are available to work with. In some OS it’s the only mechanism to get the hardware address assigned to an interface. Also, it’s possible for the route(4) (or netlink(7)) socket to overflow so it’s required to re-learn the system state which means it cannot be cached. Not that FreeBSD supports reporting route(4) overflow, but that’s another story.

Due to the getifaddrs(3) show stopper, I decided to look into OpenBSDs pledge(2). While the documentation is still very technical, it’s easier to read and understand compared to Capsicum. It’s also really really really easy to implement in comparison as you only pledge features rather than each file descriptor. Because of this, it’s also very granular. The initial commit to enable pledge is mainly allowing the current ioctl IPC framework to pass data back again.

But can we do better? Can we operate with the same Pledges that OpenBSDs dhclient(8) uses? The answer is of course YES! By caching some initial data that does not change such as utsname and machine uuid AND moving all file IO to privsep, this commit allows almost perfect Pledge support. We could go better if privsep gains support for the SIOCGIFGROUP ioctl as this would allow the inet pledge to be dropped. It’s not quite perfect because a Pledged process cannot change a BPF filter. We would need to space a BPF process per address which is then limited by the number of BPF instances you are allowed. I’m not sure this a good thing, and ironically BPF processes are the one thing we have in Capsicums capability mode. This is also a massive improvement over the initial dhcpcd-9 release because it means we no longer need any files in the chroot directory and /var/empty can be used again. This alone should make current and new FreeBSD users of dhcpcd quite happy. It will also go some way to enabling capabilities mode for the master dhcpcd process in the future.

Now, I can’t say which technology is more secure- that’s really not my field of expertise. I can’t even say if either are really needed or actually make security worse because Privilege Separation IPC adds more code, complexity and as such could make it more prone to bugs some of which could be a security attack vector in itself.

But what I can say is that Pledge is much easier to develop for because it’s really granular unlike Capsicum which is either on or off or per fd limited.

I’ll continue working on Capsicum support in dhcpcd just to see if I can enable Capabilites Mode in the master process. When that’s finished I will do a more in-depth comparison of these two technologies.