Re: rights(4) split? CAP_WRITE -> CAP_WRITE_DATA + CAP_WRITE_CTRL

Mark Johnston <[email protected]> Wed, 3 Jun 2026 16:46:27 -0400
Newsgroups gmane.os.freebsd.architechture,gmane.os.freebsd.devel.hackers
Message-ID <aiCSo77RM5qjMaUx@nuc>
On Wed, Jun 03, 2026 at 09:15:11AM -0500, Kyle Evans wrote:
> On 6/3/26 03:04, Mariusz Zaborski wrote:
> > Hello,
> > 
> > I think the idea of splitting CAP_WRITE into CAP_WRITE_DATA and CAP_WRITE_CTRL makes sense, especially for cases where a process should be able to exchange data but not transfer file descriptors.
> > 
> >  From my perspective, the biggest concern is the capability change itself. While source compatibility can largely be preserved by making CAP_WRITE an alias for CAP_WRITE_DATA | CAP_WRITE_CTRL, there is still some potential for compatibility issues with existing applications and binaries that rely on the current semantics of CAP_WRITE.
> > 
> 
> My alternative proposal would be that we slice off two entirely new bits in index 1 and still make `CAP_WRITE` an alias, but rename the current assignment to `CAP_WRITE_COMPAT`.  We don't have any precedent for it, but I'd then handle translation at the cap_rights_*(2) border and unset the new `CAP_WRITE` if `CAP_WRITE_COMPAT` is unset when limiting, and unset `CAP_WRITE_LEGACY` if *either* of the new `CAP_WRITE_*` rights are missing.

Just a couple of comments:
- Why CAP_WRITE_* instead of CAP_SEND_*?  CAP_WRITE and CAP_SEND are
  aliased today, but now that you're introducing rights specific to
  sockets, CAP_SEND_* seems clearer.
- Rather than allocating new bits, maybe we should consider repurposing
  some indices which are only used with other file types?  For instance,
  CAP_PDKILL can only ever apply to procdescs, CAP_INOTIFY_* only apply
  to inotify descriptors, etc..  There are still a fair number of bits
  left, but it wouldn't be too hard to run out of them.  Is there some
  reason we can't define aliased rights?

> I don't know how I feel about it, but I bet it would work.
> 
> > Other than that, the use case seems reasonable, and being able to explicitly prohibit SCM_RIGHTS on a socketpair could be a useful hardening measure
> > 
> > Thanks,
> > Mariusz
> > 
> > 
> > On Tue, 2 Jun 2026 at 20:19, Kyle Evans <[email protected] <mailto:[email protected]>> wrote:
> > 
> >     Hi,
> > 
> >     I'm looking at an application where it would be useful to be able to construct a socketpair(2) that can't be used to send fds over, out of an abundance of caution.  The application in prison0 is effectively a broker between two jails that it hands each an end of the socketpair, then steps out of the way -- I don't see a reason to leave it capable of carrying SCM_RIGHTS.
> > 
> >     I'd like to propose splitting CAP_WRITE into CAP_WRITE_DATA and CAP_WRITE_CTRL, with CAP_WRITE being an alias for DATA|CTRL.  The caveat is that I don't know if being able to revoke data but not control messages is really feasible or useful, off-hand.
> > 
> >     In any event, my plan would be to use the last bit available in rights idx 0 for the CTRL right, rename the current CAP_WRITE to CAP_WRITE_DATA, and create a new CAP_WRITE name for the two combined.   There's some chance for breakage in applications that haven't been rebuilt with the new definition of CAP_WRITE, but I suspect most of them aren't attempting to send control messages.  The in-kernel users of CAP_WRITE look like they could mostly be scoped down to CAP_WRITE_DATA specifically, though maybe that gets a little awkward in `flags_to_rights` mapping of O_WRONLY/O_RDWR.
> > 
> >     Thoughts? Terrible idea?
> > 
> >     Thanks,
> > 
> >     Kyle Evans
> > 
> 
>