freenode
Kernel & Low-Level

BPF exceptions may soon release locks and refs on the way out

A 29-patch series from Kumar Kartikeya Dwivedi would let bpf_throw() unwind frames that still hold kernel resources, which the verifier currently forbids.

Linux BPF programs would be allowed to throw an exception while still holding locks, object references, iterators, saved IRQ flags, or an RCU or preemption-disabled section, under a series Kumar Kartikeya Dwivedi posted to the BPF kernel mailing list. Today the verifier rejects bpf_throw() in those cases, so assertions are unusable in the places programs most often want them: a loop over an iterator, under a lock, or inside an RCU section.

A throw does not return. It unwinds to the main program's exception callback and discards every frame in between. Anything those frames still hold would leak, which is why the check exists. The series teaches the unwinder to release those resources as it walks the discarded frames, for the main program and for static and global subprograms.

To release a resource the unwinder needs a handle: a pointer to an object, a ring buffer record or a lock, or the stack address of an iterator or of saved IRQ flags. Where every path through a call that might throw keeps that handle in the same register or stack slot, the verifier records the location and the program pays nothing extra at runtime. Where the paths disagree, it reserves a hidden stack slot, stores the handle when the resource is acquired, and clears it on release. RCU and preemption sections are counted the same way. A resource released before the next call that might throw needs neither.

An automated reviewer on the list raised a run of high-severity questions about the new path, including IRQ state when a spinlock and saved flags are released together, lock and iterator ordering across frames, a possible double free if the wrong hidden slot is cleared, and whether a later NULL return can overwrite a live handle. Those are review questions, not confirmed defects, and the posting does not yet include a response.