On 10.5.2023. 0:24, Alexandr Nedvedicky wrote:
> Hello,
>
>
> On Tue, May 09, 2023 at 06:26:43PM +0000, mabi wrote:
>> Hi,
>>
>> On a brand new OpenBSD 7.3 firewall (amd64) I get a kernel panic every few
>> days and was wondering if this panic I get is related to this issue/bug?
>>
>
> your panic got fixed by recent commit [1]
>
> Hrvoje was/is hitting very close to that KASSERT() (now removed) at line 2274.
> in Hrvoje's case the TAILQ_REMOVE() macro complains we attempt to remove state
> which is removed already:
>
> 2273 atomic_sub_long(&sc->sc_len, pfsync_qs[q].len);
> 2274 TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
> 2275 if (TAILQ_EMPTY(&sc->sc_qs[q]))
> 2276 atomic_sub_long(&sc->sc_len, sizeof (struct
> pfsync_subheader));
> 2277 st->sync_state = PFSYNC_S_NONE;
> 2278 mtx_leave(&sc->sc_st_mtx);
> 2279
> 2280 pf_state_unref(st);
>
> the cause is very similar pfsync relies on volatile value in ->sync_state
> member.
> The ->sync_state member must be modified under protection of ->mtx.
>
> The issue has been pointed out by bluhm@ during m2k23 hackathon where I shared
> my pfsync(4) headache with him. Diff below is my attempt to fix it. I had no
> chance to test it. I'll appreciate If you will give it a try and let me know
> how things look like.
>
> thanks and
> regards
> sashan
>
> [1] https://marc.info/?l=openbsd-cvs&m=168269695603160&w=2
>
>
Hi,
with this diff I can't trigger panic below
r620-1# uvm_fault(0xffffffff82598710, 0x17, 0, 2) -> e
kernel: page fault trap, code=2
Stopped at pfsync_q_del+0x8d: movq %rdx,0x8(%rax)
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*254020 58090 0 0x14000 0x200 0K systq
pfsync_q_del(fffffd8360adf6e0) at pfsync_q_del+0x8d
pfsync_delete_state(fffffd8360adf6e0) at pfsync_delete_state+0x118
pf_remove_state(fffffd8360adf6e0) at pf_remove_state+0x156
pf_purge_expired_states(2e9c1) at pf_purge_expired_states+0x273
pf_purge(ffffffff8258caa0) at pf_purge+0x2c
taskq_thread(ffffffff824a8150) at taskq_thread+0x100
end trace frame: 0x0, count: 9
https://www.openbsd.org/ddb.html describes the minimum info required in bug
reports. Insufficient info makes it difficult to find and fix bugs.
ddb{0}>
I'm only being able to trigger it in lab and quite fast. Now, after few
hours it's still stable.
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
> index 822b4211d0f..811d9d59666 100644
> --- a/sys/net/if_pfsync.c
> +++ b/sys/net/if_pfsync.c
> @@ -1362,14 +1362,17 @@ pfsync_grab_snapshot(struct pfsync_snapshot *sn,
> struct pfsync_softc *sc)
>
> while ((st = TAILQ_FIRST(&sc->sc_qs[q])) != NULL) {
> TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
> + mtx_enter(&st->mtx);
> if (st->snapped == 0) {
> TAILQ_INSERT_TAIL(&sn->sn_qs[q], st, sync_snap);
> st->snapped = 1;
> + mtx_leave(&st->mtx);
> } else {
> /*
> * item is on snapshot list already, so we can
> * skip it now.
> */
> + mtx_leave(&st->mtx);
> pf_state_unref(st);
> }
> }
> @@ -1422,11 +1425,13 @@ pfsync_drop_snapshot(struct pfsync_snapshot *sn)
> continue;
>
> while ((st = TAILQ_FIRST(&sn->sn_qs[q])) != NULL) {
> + mtx_enter(&st->mtx);
> KASSERT(st->sync_state == q);
> KASSERT(st->snapped == 1);
> TAILQ_REMOVE(&sn->sn_qs[q], st, sync_snap);
> st->sync_state = PFSYNC_S_NONE;
> st->snapped = 0;
> + mtx_leave(&st->mtx);
> pf_state_unref(st);
> }
> }
> @@ -1665,6 +1670,7 @@ pfsync_sendout(void)
>
> count = 0;
> while ((st = TAILQ_FIRST(&sn.sn_qs[q])) != NULL) {
> + mtx_enter(&st->mtx);
> TAILQ_REMOVE(&sn.sn_qs[q], st, sync_snap);
> KASSERT(st->sync_state == q);
> KASSERT(st->snapped == 1);
> @@ -1672,6 +1678,7 @@ pfsync_sendout(void)
> st->snapped = 0;
> pfsync_qs[q].write(st, m->m_data + offset);
> offset += pfsync_qs[q].len;
> + mtx_leave(&st->mtx);
>
> pf_state_unref(st);
> count++;
> @@ -1725,8 +1732,6 @@ pfsync_insert_state(struct pf_state *st)
> ISSET(st->state_flags, PFSTATE_NOSYNC))
> return;
>
> - KASSERT(st->sync_state == PFSYNC_S_NONE);
> -
> if (sc->sc_len == PFSYNC_MINPKT)
> timeout_add_sec(&sc->sc_tmo, 1);
>
> @@ -2221,6 +2226,7 @@ pfsync_q_ins(struct pf_state *st, int q)
> panic("pfsync pkt len is too low %zd", sc->sc_len);
> do {
> mtx_enter(&sc->sc_st_mtx);
> + mtx_enter(&st->mtx);
>
> /*
> * There are either two threads trying to update the
> @@ -2228,6 +2234,7 @@ pfsync_q_ins(struct pf_state *st, int q)
> * (is on snapshot queue).
> */
> if (st->sync_state != PFSYNC_S_NONE) {
> + mtx_leave(&st->mtx);
> mtx_leave(&sc->sc_st_mtx);
> break;
> }
> @@ -2240,6 +2247,7 @@ pfsync_q_ins(struct pf_state *st, int q)
> sclen = atomic_add_long_nv(&sc->sc_len, nlen);
> if (sclen > sc->sc_if.if_mtu) {
> atomic_sub_long(&sc->sc_len, nlen);
> + mtx_leave(&st->mtx);
> mtx_leave(&sc->sc_st_mtx);
> pfsync_sendout();
> continue;
> @@ -2249,6 +2257,7 @@ pfsync_q_ins(struct pf_state *st, int q)
>
> TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
> st->sync_state = q;
> + mtx_leave(&st->mtx);
> mtx_leave(&sc->sc_st_mtx);
> } while (0);
> }
> @@ -2260,6 +2269,7 @@ pfsync_q_del(struct pf_state *st)
> int q;
>
> mtx_enter(&sc->sc_st_mtx);
> + mtx_enter(&st->mtx);
> q = st->sync_state;
> /*
> * re-check under mutex
> @@ -2267,6 +2277,7 @@ pfsync_q_del(struct pf_state *st)
> * too late, the state is being just processed/dispatched to peer.
> */
> if ((q == PFSYNC_S_NONE) || (st->snapped)) {
> + mtx_leave(&st->mtx);
> mtx_leave(&sc->sc_st_mtx);
> return;
> }
> @@ -2275,6 +2286,7 @@ pfsync_q_del(struct pf_state *st)
> if (TAILQ_EMPTY(&sc->sc_qs[q]))
> atomic_sub_long(&sc->sc_len, sizeof (struct pfsync_subheader));
> st->sync_state = PFSYNC_S_NONE;
> + mtx_leave(&st->mtx);
> mtx_leave(&sc->sc_st_mtx);
>
> pf_state_unref(st);
>