Page MenuHomeFreeBSD

ipfw: make the upper half lock sleepable
ClosedPublic

Authored by glebius on Jan 5 2026, 7:38 PM.
Tags
None
Referenced Files
F145681708: D54535.id.diff
Mon, Feb 23, 1:32 AM
Unknown Object (File)
Wed, Feb 18, 10:59 AM
Unknown Object (File)
Fri, Jan 30, 4:51 PM
Unknown Object (File)
Wed, Jan 28, 7:30 PM
Unknown Object (File)
Sun, Jan 25, 9:41 AM
Unknown Object (File)
Jan 20 2026, 12:19 PM
Unknown Object (File)
Jan 20 2026, 7:19 AM
Unknown Object (File)
Jan 18 2026, 8:08 AM

Details

Summary

The so called upper half ipfw lock is not used in the forwarding path. It
is used only during configuration changes and servicing system events like
interface arrival/departure or vnet creation. The original code drops the
lock before malloc(M_WAITOK) and then goes into great efforts to recover
from possible races. But the races still exist, e.g. create_table() would
first check for table existence, but then drop the lock. The change also
fixes unlock leak in check_table_space() in a branch that apparently was
never entered.

Changing to a sleepable lock we can reduce a lot of existing complexity
associated with race recovery, and as use the lock to cover other
configuration time allocations, like recently added per-rule bpf(4) taps.

This change doesn't remove much of a race recovery code, to ease bisection
in case of a regression. This will be done in a separate commit. This
change just removes lock drops during configuration events. The only
reduction is removal of get_map(), which is a straightforward reduce to a
simple malloc(9).

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 69632
Build 66515: arc lint + arc unit

Event Timeline

  • Fix lock leak in ipfw_commit_rules().
The only sleepable context where the lock was acquired was dyn_tick(). The
comment said it is done to prevent parallel execution of
dyn_expire_states().  However, there is proper internal locking in there
and function should be safe to execute in parallel.  The real problem is
dyn_expire_states() called via userland to race with dyn_grow_hashtable()
called via dyn_tick().  Protect against this condition with the main chain
lock.
sys/netpfil/ipfw/ip_fw_table.c
1079

While you are here, it seems there is missing IPFW_UH_RUNLOCK.

sys/netpfil/ipfw/ip_fw_table.c
1079

I'd better assert that table implementation can find an entry :) Will make a separate commit.

This revision was not accepted when it landed; it landed in state Needs Review.Jan 17 2026, 12:46 AM
This revision was automatically updated to reflect the committed changes.