back
1 comments
ebpf used in this way is typically nonblocking. it drops data instead of blocking. for a firewall, that’s potentially bad.

can ebpf operate in a blocking manner while making drop/allow decisions on packets WITH reliable access to the callers pid and argv?

I think OpenSnitch just uses eBPF to capture metadata about the new connection, the "hold for user confirmation" does not happen inside eBPF. The eBPF does not need to block waiting for user input.

https://github.com/evilsocket/opensnitch/blob/4ce8b0e57cfb25... https://github.com/evilsocket/opensnitch/blob/d9e0c59158ddf6...

by the time a user prompt is displayed, all metadata has been joined to the packet, and libnetfilterqueue is waiting for a decision.

my understanding of what is happening is as follows:

- 1: libnetfilterqueue gets a packet.

- 2: lookup packet via ebpf to get pid and argv.

- 3: lookup rule, on miss prompt user to allow/deny.

- 4: libnetfilterqueue allows/denies the packet.

the tricky part is step 2. afaik there are 3 possibilities:

- ebpf already knows about about this packet, return pid and argv.

- ebpf will know about this packet shortly, wait, then return pid and argv.

- ebpf dropped the data because of ringbuffer overflow, wait, then give up.

My understanding: ebpf runs at connect(2) time, stores metadata in a map; later, an NFQUEUE userspace helper fetches the metadata from the map.
this is correct. it's the datarace between these components, and the possibility of ebpf dropping data because of a slow userspace callback, that makes this flaky.
Very cool! I also found it recently submitted to HN: https://news.ycombinator.com/item?id=31160863
> for a firewall, that’s potentially bad

I wasn't talking about using it as a firewall, just a connection/bandwidth monitor that correlates traffic with a particular app.

bandwidth monitor use case seems like a perfect fit, and the occasional missed packet wouldn’t be an issue.

picosnitch looks really cool! i’ve rss subscribed to its github commits.

Thanks! Also I used lost_cb [0] to detect if a packet or connection (with security_socket_connect) was missed between the BPF and Python parts, but is it possible for the BPF program to miss either entirely without triggering that callback?

If so (without a kernel vulnerability which should be a given) I'd like to have it mentioned under the limitations section for picosnitch so others can be aware as well.

[0] https://github.com/iovisor/bcc/blob/master/docs/reference_gu...

i don’t think so. i think exactly what you’ve documented is the case. if the callback can’t keep up with the data before the ringbuffer overflows, data is lost. in that case, the solution is to increase the size of the ringbuffer, giving the callback a larger window to keep up with incoming data bursts.

in the end there are only two ways to handle this: drop data or block. for a bandwidth monitor, i’d choose drop. for a firewall, i’d choose block.

i use bpftrace to monitor docker filesystem access in a similar way[1]. i also increase the ringbuffer size until i stop seeing lost data.

1. https://github.com/nathants/docker-trace#files