On Tue, Sep 29, 2026 at 10:02:25PM +0200, Alexandr Nedvedicky wrote:
> Hello,
> 
> 
> On Mon, Sep 28, 2026 at 11:07:44AM +0200, alf wrote:
> </snip>
> > 
> > output of screenshots of the vultr console parsed by OCR
> > and hand edited by me:
> > o8 0 0 0
> > 110011557 41e622,,   0,   1 )  - >    e
> > 1kernel: page fault trap, code=0          ,
> > Stopped at      rn_match+0x44:  movzbl  0(%rdi,%rax,1),%eax
> >    TID    PID    UID     PRfLAGS     PFLAGS  CPU  COMMAND
> >  477789  49437      0    0x14000     0x200   0  softnet1
> > *425356  21547      0    0x14000     0x200   2  softnet0
> > rn_match(ffff80003165d010,ffff800000c3f600) at rn_match+0x44
> > pfr_lookup_addr(ffff800016fdcfc0,ffff80003165d0e8,1) at pfr_lookup_addr+0xfb
> > pfr_insert_kentry(ffff800016fdcfc0,ffff80003165d0e8,6a8f74d8) at 
> > pfr_insert_ken
> >  try+0x32
> > pff_src_connlimit(ffff80003165d3f0) at pf_src_connlimit+0x20a
> > pff_tcp_track_full(ffff80003165d300,ffff80003165d3f0,ffff80003165d3fe,ffff800031
> > 65d254,0) at pf_tcp_track_full+0xcbc
> > pf_test_state(ffff80003165d300,ffff80003165d3f0,ffff80003165d3fe) at 
> > pf_test_st
> > ate+0xb03
> > pf_test(18,1,ffff800000057858,ffff80003165d578) at pf_test+0xfcd
> > ip6_input_if(ffff80003165d578,ffff80003165d584,29,0,ffff800000057858,fffffff82
> > bb4358) at ip6_input_if+0x1e9
> > ipv6_input(ffff800000057858,fffffd80be095400,ffffffff82bb4358) at 
> > ipv6_input+0x
> > 42
> 
>     the problem is pf(4) updates overload table without holding a PF_LOCK().
>     pf(4) holds state lock to find state, then it grabs reference and drops 
> the
>     state lock. however if state is created on behalf of rule with overload
>     action, pf(4) must lock PF_LOCK() and eventually state table when calling
>     to pf_src_connlimit(). 
> 
> patch below should help to make your firewall stable.
> 
> I tested the change with rules as follows:
> 
> table <minute>
> 
> pass all
> 
> block in on vio2
> block return in quick on vio2 from <minute> to any
> pass in on vio2 from 10.188.212.0/24 to any keep state (max-src-conn-rate 
> 1/1, overload <minute>)
> 
> 
> thanks for very helpful bug report. hope the patch below will help you.
> 
> regards
> sashan

Thanks,

I backported (it didn't like the first hunk) the patch to 7.9-STABLE since 
that's
what we're running here, built and installed a new kernel and enabled 
rate-limiting
again.

I'll report back how it goes,

Alf

> 
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sys/net/pf.c b/sys/net/pf.c
> index b465a77b487..e6c67842a07 100644
> --- a/sys/net/pf.c
> +++ b/sys/net/pf.c
> @@ -757,9 +757,12 @@ pf_src_connlimit(struct pf_state **stp)
>       int                      bad = 0;
>       struct pf_src_node      *sn;
>       u_int32_t                sn_conn;
> +     int                      rv = 0;
> +
> +     PF_LOCK();
>  
>       if ((sn = pf_get_src_node((*stp), PF_SN_NONE)) == NULL)
> -             return (0);
> +             goto done;
>  
>       /*
>        * Note: conn limit is bumped on SYN_SENT->ESTBLISHED
> @@ -784,7 +787,7 @@ pf_src_connlimit(struct pf_state **stp)
>       }
>  
>       if (!bad)
> -             return (0);
> +             goto done;
>  
>       if ((*stp)->rule.ptr->overload_tbl) {
>               struct pfr_addr p;
> @@ -822,6 +825,7 @@ pf_src_connlimit(struct pf_state **stp)
>                       struct pf_state *st;
>  
>                       pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
> +                     PF_STATE_ENTER_READ();
>                       RBT_FOREACH(st, pf_state_tree_id, &tree_id) {
>                               sk = st->key[PF_SK_WIRE];
>                               /*
> @@ -844,6 +848,7 @@ pf_src_connlimit(struct pf_state **stp)
>                                       killed++;
>                               }
>                       }
> +                     PF_STATE_EXIT_READ();
>                       if (pf_status.debug >= LOG_NOTICE)
>                               addlog(", %u states killed", killed);
>               }
> @@ -854,7 +859,12 @@ pf_src_connlimit(struct pf_state **stp)
>       /* kill this state */
>       pf_update_state_timeout(*stp, PFTM_PURGE);
>       pf_set_protostate(*stp, PF_PEER_BOTH, TCPS_CLOSED);
> -     return (1);
> +
> +     rv = 1;
> +done:
> +     PF_UNLOCK();
> +
> +     return (rv);
>  }
>  
>  int
> 

Reply via email to