On Nov 12, 2025, at 3:38 AM, Theo de Raadt <[email protected]> wrote:
> I'll let others handle the new instructions, but wanted to comment on > this piece. > > +++ share/man/man4/bpf.4 10 Nov 2025 20:51:14 -0000 > @@ -189,6 +189,9 @@ > .Dv BIOCGSTATS . > .Pp > .It Dv BIOCLOCK > +Sets the locked flag on the > +.Nm > +descriptor. That was something I noted a while ago but hadn't sent to [email protected]; the previous text didn't say what the ioctl *did*. > The full block of text once expanded: > > BIOCLOCK > This ioctl is designed to prevent the security issues associated > with an open bpf descriptor in unprivileged programs. Even with > dropped privileges, an open bpf descriptor can be abused by a > rogue program to listen on any interface on the system, send > packets on these interfaces if the descriptor was opened read- > write and send signals to arbitrary processes using the signaling > mechanism of bpf. By allowing only "known safe" ioctls, the > BIOCLOCK ioctl prevents this abuse. The allowable ioctls are > BIOCFLUSH, BIOCGBLEN, BIOCGDIRFILT, BIOCGDLT, BIOCGDIRFILT, > BIOCGDLTLIST, BIOCGETIF, BIOCGHDRCMPLT, BIOCGRSIG, BIOCGRTIMEOUT, > BIOCGSTATS, BIOCIMMEDIATE, BIOCLOCK, BIOCSRTIMEOUT, > BIOCSWTIMEOUT, BIOCDWTIMEOUT, BIOCVERSION, TIOCGPGRP, and > FIONREAD. Use of any other ioctl is denied with error EPERM. > Once a descriptor is locked, it is not possible to unlock it. A > process with root privileges is not affected by the lock. > > A privileged program can open a bpf device, drop privileges, set > the interface, filters and modes on the descriptor, and lock it. > Once the descriptor is locked, the system is safe from further > abuse through the descriptor. Locking a descriptor does not > prevent writes. If the application does not need to send packets > through bpf, it can open the device read-only to prevent writing. > If sending packets is necessary, a write-filter can be set before > locking the descriptor to prevent arbitrary packets from being > sent out. > > That's quite a lot of words explaining the locking mechanism and how it is > supposed to be used. And it probably belongs earlier in the man page, so that the mechanism is described before the page describes all the trees in the ioctl forest. Perhaps the Once a descriptor is configured, further changes to the configuration can be prevented using the BIOCLOCK ioctl(2). paragraph should be changed to contain the detailed description. (That section should perhaps also mention, for example, the details of buffering and filtering.) > There is strong implication that this ioctl op sets the lock which activates > this behaviour. I prefer explicit indications to implications - and if the text explaining the general mechanism is moved out of the description of the ioctl, the ioctl's would shrink to "this sets the lock". > I don't like the idea of mentioning a 'lock on the descriptor'. From a > programmer's perspective, descriptor refers to the 'fd'. But there are > other styles of locks on fd, reachable with fcntl and flock. That sounds as if "lock" is either the wrong term or should be qualified so as to distinguish it from *file* locks. > I don't like the sentence about root not being affected, and I regret > that we did this: > > if (d->bd_locked && suser(p) != 0) { > /* list of allowed ioctls when locked and not root */ > switch (cmd) { > > I wonder if we've modified enough programs that we can change this: > constrain root's abilities on a bd_locked bpf also. I.e., you're not objecting to the text of that sentence, you're objecting to the reality that the sentence describes, i.e. "root gets a free pass".
