A few days ago I posted about Capsicum vs Pledge in dhcpcd. Well, I finished the Capsicum integration yesterday so I thought I would take some time to revisit my findings.
Capsicum is hard to develop for
It’s either on or off. You can limit each FD with capabilites mode off, but I’m not sure what that gains as it’s mainly there to allow the FD to be used in the restricted world so we can treat it as either on or off really.
Pledge is granular, you can turn areas on or off. For example, you can allow full file access while restricting various ioctls. Ideally, the only thing you want to pledge is stdio, which is kinda needed for the Privilege Separation IPC to work. However, we end up pledging dns inet and route as well.
So why is Capsicum harder? Well, the short answer is that it’s not. The long answer is that it’s perceived to be harder because you have to do all the work up front to get your code working whereas Pledge allows you do it it piece meal.
Pledge is as secure as Capsicum
As I said in my prior post, I’m not a security expert, but here’s my findings:
You can make Pledge as secure as Capsicum, but you don’t have to.
As a user on OpenBSD I can see lots of processes marked with p
to indicate
they have pledged something.
As a user on FreeBSD I can see lots of processes marked with ‘C’ to indicate they are in Capsicum Capabilites Mode. Because this is just on or off, I know exactly what this process can and cannot do.
Armed with this knowledge I would trust a Capsicum enabled application more than a Pledge enabled application. But to fully trust either you still need to audit the code.
They both have limitations
With a Pledged process you cannot change a BPF filter with the bpf pledge. This is unfortunate, a possible solution could be to spawn a process AND filter for every address you want to monitor for DaD or ARP pinging. That could be a lot of resources wasted as BPF is neither infinite nor cheap.
With a Capsicum Capability Mode enabled process you cannot call sendto(2)
that is not connected.
Unlike the above, there is no easy solution.
I can’t spawn off another process because unlike normal communication,
because I need to bind to the bootpc
and dhcpv6-client
ports
so I can dictate which source port is used to send the message.
The binding would then fail because the network proxy process
is already using the port.
A possible solution is to call RTM_GET to work out which host I send to
on the local network, craft the packet by hand and send it out using a BPF
socket.
I strongly feel that both should be fixed upstream:
- the bpf Pledge should allow changing the BPF filter.
- Capsicum should allow sendto unconnected if bound to a priviledged port or another capability created to grant to the socket.
As it stands, dhcpcd does not Pledge for BPF processes and does not run the generic network proxy process in Capsicum Capabilites mode. However, both processes are using the unprivileged user and chrooted to an empty directory. Neither do any processing of data coming in, they just ferry it back to the master process via IPC which runs under the same restrictions but is also sandboxed with Pledge or Capsicum so I’m confident that it’s good enough.