In a nutshell: “Justine Tunney’s pledge() implementation works around these problems by (a) only supporting her own, simpler, libc implementation, and (b) only supporting the x86-64 architecture.”
It’s a lot easier when you’ve narrowed the problem space that dramatically.
It’s a lot easier if you control libc but I’m not sure how you do the path-based things without a supervisor process.
The key problem with seccomp-bpf is that it can’t inspect syscall arguments or kernel state in a useful way. You can’t use it to implement anything that does path-based filtering because you can’t read the path arguments. This is a general problem for any pointer arguments, not just paths. Linux has recently started moving to a model for new syscalls where they take an extensible struct and the size of that struct as an argument (see: clone3 for a great example). Any syscall of this form is completely opaque to seccomp-bpf.
In the opposite direction, it can’t do anything that involves knowledge of kernel state. This means that it can’t key off file descriptors, for example, because it doesn’t know what they correspond to and the policy is stateless and so it can’t even record the arguments for the syscall that created the file descriptor.
I have implemented a useful subst of Capsicum on seccomp-bpf, but the experience was painful and it requires doing a lot of things in the supervisor process on Linux that are safe to keep in the monitored process on FreeBSD.