OpenBSD Journal

Enable BPF filtering on sockets

Contributed by Peter N. M. Hansteen on from the BPF my daemons, Puffy! dept.

Would it be useful for our system security to let daemons use the bpf(4) interface to filter on the sockets they handle?

In a recent message to tech@ titled bpf filtering on arbitrary sockets, Damien Miller (djm@) presents a preliminary patch and explains,

List:       openbsd-tech
Subject:    bpf filtering on arbitrary sockets
From:       Damien Miller <djm () mindrot ! org>
Date:       2025-10-30 5:03:00

Hi,

This is an idea that came up while talking with dlg@ about network
daemons.

Quite a few programs and daemons use SOCK_RAW to send link-level packets
after pledge(). E.g. usr.sbin/relayd/check_icmp.c wants to send ICMP
packets.

The problem with this is that, if they get compromised, they still hold
a very powerful socket that can send pretty much arbitrary packets. If
one of these programs gets compromised then the attacker can pretty
easily pivot through the existing raw socket.
What if we allowed attaching a bpf instances to sockets? On the
receive side, these could be used to limit the types of messages
received. Similarly, on the send side, they could restrict the ability
of the socket to send arbitrary messages.

E.g. for something like ping(1), a bpf program like:

    { 0x28, 0, 0, 0x0000000c },
    { 0x15, 0, 7, 0x00000800 },
    { 0x30, 0, 0, 0x00000017 },
    { 0x15, 0, 5, 0x00000001 },
    { 0x20, 0, 0, 0x0000001a },
    { 0x15, 2, 0, src_addr },
    { 0x20, 0, 0, 0x0000001e },
    { 0x15, 0, 1, dst_addr },
    { 0x6, 0, 0, 0x00000074 },
    { 0x6, 0, 0, 0x00000000 },

could be used on the send side to drastically limit the power of the raw
socket. These programs are trivial to write using `tcpdump -dd`; with a
small tweak to tcpdump it might be possible to generate them from a
Makefile rule.

Practically, this would mean a few new setsockopt()s:

1. Attach a bpf program to a socket that filter received packets
2. Attach a bpf program to a socket that filters sent packets
3. An equivalent to BIOCLOCK to lock the bpf filters for a socket

Programs would set up their SOCK_RAW sockets as usual, then attach
the filters, then lock the filters then pledge.

Here's what this looks like for the output side.

It's pretty simple (too simple?) - there's a SOL_SOCKET SO_SEND_BPF
setsockopt that loads a bpf_program to a socket fd. Packets that fail
to match the filter are denied with EPERM.

Note that the filter is applied to just the data that is passed to
send(), sendto(), etc and not any protocol-level headers. AFAIK it
can work with any datagram socket type in addition to SOCK_RAW, so
could for example be used to limit the structure of USP messages,
etc in addition to low-level SOCK_RAW control.

There's also a SO_BPF_LOCK setsockopt that locks the program as you'd
expect.

What do you think? What would be a good daemon to try this against?
I was thinking dhcpleased but that seems to use bpf for most of its
sending, though that should IMO be converted to AF_FRAME now that we
have it.

-d

Index: kern/uipc_socket.c
===================================================================
[…]

with the patch (as always, against -current) that contains the proposed code changes in the rest of the message.

The discussion is ongoing, expect to see further development and surgery on one or more daemons in the near future.


Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]