i upgraded one of the work firewalls to -current and added the diff
below in, and got what looks like a different panic:
ddb{6}> tr
db_enter() at db_enter+0x5
panic(ffffffff81e2cc31) at panic+0xbf
__assert(ffffffff81eae23b,ffffffff81ee4549,797,ffffffff81e7fd91) at
__assert+0x25
pfsync_insert_state(fffffd816375b720) at pfsync_insert_state+0xec
pf_state_insert(ffff8000001f0000,ffff800024cd9cc0,ffff800024cd9cb8,fffffd816375b720)
at pf_state_insert+0x2df
pf_test_rule(ffff800024cd9e50,ffff800024cd9e38,ffff800024cd9e30,ffff800024cd9e40,ffff800024cd9e28,ffff800024cd9e4e,1)
at pf_test_rule+0xec4
pf_test(2,3,ffff8000016ab800,ffff800024cd9fe8) at pf_test+0x1126
ip_output(fffffd8052dae400,0,ffff800024cda0b0,1,0,0,ffff800001640801) at ip_out
put+0x72a
ip_forward(fffffd8052dae400,ffff800001640800,fffffd81840e2ad0,0) at
ip_forward+0x286
ip_input_if(ffff800024cda2e0,ffff800024cda2dc,4,0,ffff800001640800) at
ip_input_if+0x347
ipv4_input(ffff800001640800,fffffd8052dae400) at ipv4_input+0x37
ether_input(ffff800001640800,fffffd8052dae400) at ether_input+0x394
carp_input(ffff8000016a2000,fffffd8052dae400,5e000156) at carp_input+0x186
ether_input(ffff8000016a2000,fffffd8052dae400) at ether_input+0x1c5
vlan_input(ffff80000161a000,fffffd8052dae400,ffff800024cda4fc) at
vlan_input+0x22d
ether_input(ffff80000161a000,fffffd8052dae400) at ether_input+0x83
if_input_process(ffff80000019a048,ffff800024cda588) at if_input_process+0x4a
ifiq_process(ffff8000001f0800) at ifiq_process+0x8e
taskq_thread(ffff80000002c080) at taskq_thread+0xfa
end trace frame: 0x0, count: -19
ddb{6}> sh panic
*cpu6: kernel diagnostic assertion "st->sync_state == PFSYNC_S_NONE" failed:
file "/usr/src/sys/net/if_pfsync.c", line 1943
i'll try and have a look at it. i am probably most responsible for the
code :(
On Wed, Jun 08, 2022 at 12:42:33AM +0200, Alexandr Nedvedicky wrote:
> Hello Hrvoje,
>
> </snip>
> >
> > Hi,
> >
> > while booting with this diff I've got this log:
> >
> > starting early daemons: syslogd pflogd ntpdwitness: lock_object
> > uninitialized: 0xfffffd8785c81a
> > 90
> > Starting stack trace...
> > witness_checkorder(fffffd8785c81a90,9,0) at witness_checkorder+0xad
> > mtx_enter(fffffd8785c81a80) at mtx_enter+0x34
> > pf_remove_state(fffffd8785c81988) at pf_remove_state+0x1da
> > pfsync_in_del_c(fffffd80028977b0,c,2,2) at pfsync_in_del_c+0x9f
> > pfsync_input(ffff800020b056e8,ffff800020b056f4,f0,2) at pfsync_input+0x33c
> > ip_deliver(ffff800020b056e8,ffff800020b056f4,f0,2) at ip_deliver+0x103
> > ip_local(ffff800020b056e8,ffff800020b056f4,fe0000007fff0220,0) at
> > ip_local+0x1b7
> > ipintr() at ipintr+0x5f
> > if_netisr(0) at if_netisr+0xca
> > taskq_thread(ffff800000036000) at taskq_thread+0x11a
>
> thanks for quick test with pfsync. it has turned out I've forgot to
> initialize
> a pf_state::mtx in pfsync_state_import() function.
>
> below is updated diff, which should fix a stack trace reported by witness.
>
> thanks and
> regards
> sashan
>
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
> index c78ca62766e..b039a50a7bb 100644
> --- a/sys/net/if_pfsync.c
> +++ b/sys/net/if_pfsync.c
> @@ -157,16 +157,16 @@ struct {
> };
>
> struct pfsync_q {
> - void (*write)(struct pf_state *, void *);
> + int (*write)(struct pf_state *, void *);
> size_t len;
> u_int8_t action;
> };
>
> /* we have one of these for every PFSYNC_S_ */
> -void pfsync_out_state(struct pf_state *, void *);
> -void pfsync_out_iack(struct pf_state *, void *);
> -void pfsync_out_upd_c(struct pf_state *, void *);
> -void pfsync_out_del(struct pf_state *, void *);
> +int pfsync_out_state(struct pf_state *, void *);
> +int pfsync_out_iack(struct pf_state *, void *);
> +int pfsync_out_upd_c(struct pf_state *, void *);
> +int pfsync_out_del(struct pf_state *, void *);
>
> struct pfsync_q pfsync_qs[] = {
> { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
> @@ -516,10 +516,10 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
> return (0);
> }
>
> -void
> +int
> pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
> {
> - pf_state_export(sp, st);
> + return (pf_state_export(sp, st));
> }
>
> int
> @@ -680,6 +680,7 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
> st->sync_state = PFSYNC_S_NONE;
>
> refcnt_init(&st->refcnt);
> + mtx_init(&st->mtx, IPL_NET);
>
> /* XXX when we have anchors, use STATE_INC_COUNTERS */
> r->states_cur++;
> @@ -1529,24 +1530,25 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t
> data)
> return (0);
> }
>
> -void
> +int
> pfsync_out_state(struct pf_state *st, void *buf)
> {
> struct pfsync_state *sp = buf;
>
> - pfsync_state_export(sp, st);
> + return (pfsync_state_export(sp, st));
> }
>
> -void
> +int
> pfsync_out_iack(struct pf_state *st, void *buf)
> {
> struct pfsync_ins_ack *iack = buf;
>
> iack->id = st->id;
> iack->creatorid = st->creatorid;
> + return (0);
> }
>
> -void
> +int
> pfsync_out_upd_c(struct pf_state *st, void *buf)
> {
> struct pfsync_upd_c *up = buf;
> @@ -1557,9 +1559,10 @@ pfsync_out_upd_c(struct pf_state *st, void *buf)
> pf_state_peer_hton(&st->dst, &up->dst);
> up->creatorid = st->creatorid;
> up->timeout = st->timeout;
> + return (0);
> }
>
> -void
> +int
> pfsync_out_del(struct pf_state *st, void *buf)
> {
> struct pfsync_del_c *dp = buf;
> @@ -1568,6 +1571,7 @@ pfsync_out_del(struct pf_state *st, void *buf)
> dp->creatorid = st->creatorid;
>
> SET(st->state_flags, PFSTATE_NOSYNC);
> + return (0);
> }
>
> void
> @@ -1881,8 +1885,8 @@ pfsync_sendout(void)
> KASSERT(st->snapped == 1);
> st->sync_state = PFSYNC_S_NONE;
> st->snapped = 0;
> - pfsync_qs[q].write(st, m->m_data + offset);
> - offset += pfsync_qs[q].len;
> + if (pfsync_qs[q].write(st, m->m_data + offset) == 0)
> + offset += pfsync_qs[q].len;
>
> pf_state_unref(st);
> count++;
> diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
> index bee6c77f228..4440a561854 100644
> --- a/sys/net/if_pfsync.h
> +++ b/sys/net/if_pfsync.h
> @@ -326,7 +326,7 @@ int pfsync_sysctl(int *, u_int,
> void *, size_t *,
> #define PFSYNC_SI_CKSUM 0x02
> #define PFSYNC_SI_ACK 0x04
> int pfsync_state_import(struct pfsync_state *, int);
> -void pfsync_state_export(struct pfsync_state *,
> +int pfsync_state_export(struct pfsync_state *,
> struct pf_state *);
>
> void pfsync_insert_state(struct pf_state *);
> diff --git a/sys/net/pf.c b/sys/net/pf.c
> index 93fe5702625..c76f4c71263 100644
> --- a/sys/net/pf.c
> +++ b/sys/net/pf.c
> @@ -185,7 +185,8 @@ int pf_translate_icmp_af(struct
> pf_pdesc*, int, void *);
> void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, int,
> sa_family_t, struct pf_rule *, u_int);
> void pf_detach_state(struct pf_state *);
> -void pf_state_key_detach(struct pf_state *, int);
> +void pf_state_key_detach(struct pf_state *,
> + struct pf_state_key *);
> u_int32_t pf_tcp_iss(struct pf_pdesc *);
> void pf_rule_to_actions(struct pf_rule *,
> struct pf_rule_actions *);
> @@ -260,6 +261,9 @@ void
> pf_state_key_unlink_inpcb(struct pf_state_key *);
> void pf_inpcb_unlink_state_key(struct inpcb *);
> void pf_pktenqueue_delayed(void *);
> int32_t pf_state_expires(const struct pf_state *,
> uint8_t);
> +void pf_state_keys_take(struct pf_state *,
> + struct pf_state_key **);
> +void pf_state_keys_rele(struct pf_state_key **);
>
> #if NPFLOG > 0
> void pf_log_matches(struct pf_pdesc *, struct pf_rule *,
> @@ -778,7 +782,8 @@ pf_state_key_attach(struct pf_state_key *sk, struct
> pf_state *s, int idx)
> s->key[idx] = sk;
>
> if ((si = pool_get(&pf_state_item_pl, PR_NOWAIT)) == NULL) {
> - pf_state_key_detach(s, idx);
> + pf_state_key_detach(s, s->key[idx]);
> + s->key[idx] = NULL;
> return (-1);
> }
> si->s = s;
> @@ -798,42 +803,50 @@ pf_state_key_attach(struct pf_state_key *sk, struct
> pf_state *s, int idx)
> void
> pf_detach_state(struct pf_state *s)
> {
> - if (s->key[PF_SK_WIRE] == s->key[PF_SK_STACK])
> - s->key[PF_SK_WIRE] = NULL;
> + struct pf_state_key *key[2];
> +
> + mtx_enter(&s->mtx);
> + key[PF_SK_WIRE] = s->key[PF_SK_WIRE];
> + key[PF_SK_STACK] = s->key[PF_SK_STACK];
> + s->key[PF_SK_WIRE] = NULL;
> + s->key[PF_SK_STACK] = NULL;
> + mtx_leave(&s->mtx);
> +
> + if (key[PF_SK_WIRE] == key[PF_SK_STACK])
> + key[PF_SK_WIRE] = NULL;
>
> - if (s->key[PF_SK_STACK] != NULL)
> - pf_state_key_detach(s, PF_SK_STACK);
> + if (key[PF_SK_STACK] != NULL)
> + pf_state_key_detach(s, key[PF_SK_STACK]);
>
> - if (s->key[PF_SK_WIRE] != NULL)
> - pf_state_key_detach(s, PF_SK_WIRE);
> + if (key[PF_SK_WIRE] != NULL)
> + pf_state_key_detach(s, key[PF_SK_WIRE]);
> }
>
> void
> -pf_state_key_detach(struct pf_state *s, int idx)
> +pf_state_key_detach(struct pf_state *s, struct pf_state_key *key)
> {
> struct pf_state_item *si;
> - struct pf_state_key *sk;
>
> - if (s->key[idx] == NULL)
> + PF_STATE_ASSERT_LOCKED();
> +
> + if (key == NULL)
> return;
>
> - si = TAILQ_FIRST(&s->key[idx]->states);
> + si = TAILQ_FIRST(&key->states);
> while (si && si->s != s)
> si = TAILQ_NEXT(si, entry);
>
> if (si) {
> - TAILQ_REMOVE(&s->key[idx]->states, si, entry);
> + TAILQ_REMOVE(&key->states, si, entry);
> pool_put(&pf_state_item_pl, si);
> }
>
> - sk = s->key[idx];
> - s->key[idx] = NULL;
> - if (TAILQ_EMPTY(&sk->states)) {
> - RB_REMOVE(pf_state_tree, &pf_statetbl, sk);
> - sk->removed = 1;
> - pf_state_key_unlink_reverse(sk);
> - pf_state_key_unlink_inpcb(sk);
> - pf_state_key_unref(sk);
> + if (TAILQ_EMPTY(&key->states)) {
> + RB_REMOVE(pf_state_tree, &pf_statetbl, key);
> + key->removed = 1;
> + pf_state_key_unlink_reverse(key);
> + pf_state_key_unlink_inpcb(key);
> + pf_state_key_unref(key);
> }
> }
>
> @@ -996,7 +1009,9 @@ pf_state_insert(struct pfi_kif *kif, struct pf_state_key
> **skw,
> }
> *skw = s->key[PF_SK_WIRE];
> if (pf_state_key_attach(*sks, s, PF_SK_STACK)) {
> - pf_state_key_detach(s, PF_SK_WIRE);
> + pf_state_key_detach(s, s->key[PF_SK_WIRE]);
> + s->key[PF_SK_WIRE] = NULL;
> + *skw = NULL;
> PF_STATE_EXIT_WRITE();
> return (-1);
> }
> @@ -1185,30 +1200,35 @@ pf_find_state_all(struct pf_state_key_cmp *key, u_int
> dir, int *more)
> return (ret ? ret->s : NULL);
> }
>
> -void
> +int
> pf_state_export(struct pfsync_state *sp, struct pf_state *st)
> {
> int32_t expire;
> + struct pf_state_key *key[2] = { NULL, NULL };
>
> memset(sp, 0, sizeof(struct pfsync_state));
>
> /* copy from state key */
> - sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
> - sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
> - sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
> - sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
> - sp->key[PF_SK_WIRE].rdomain = htons(st->key[PF_SK_WIRE]->rdomain);
> - sp->key[PF_SK_WIRE].af = st->key[PF_SK_WIRE]->af;
> - sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
> - sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
> - sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
> - sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
> - sp->key[PF_SK_STACK].rdomain = htons(st->key[PF_SK_STACK]->rdomain);
> - sp->key[PF_SK_STACK].af = st->key[PF_SK_STACK]->af;
> + pf_state_keys_take(st, key);
> + if ((key[PF_SK_WIRE] == NULL) || (key[PF_SK_STACK] == NULL))
> + return (-1);
> +
> + sp->key[PF_SK_WIRE].addr[0] = key[PF_SK_WIRE]->addr[0];
> + sp->key[PF_SK_WIRE].addr[1] = key[PF_SK_WIRE]->addr[1];
> + sp->key[PF_SK_WIRE].port[0] = key[PF_SK_WIRE]->port[0];
> + sp->key[PF_SK_WIRE].port[1] = key[PF_SK_WIRE]->port[1];
> + sp->key[PF_SK_WIRE].rdomain = htons(key[PF_SK_WIRE]->rdomain);
> + sp->key[PF_SK_WIRE].af = key[PF_SK_WIRE]->af;
> + sp->key[PF_SK_STACK].addr[0] = key[PF_SK_STACK]->addr[0];
> + sp->key[PF_SK_STACK].addr[1] = key[PF_SK_STACK]->addr[1];
> + sp->key[PF_SK_STACK].port[0] = key[PF_SK_STACK]->port[0];
> + sp->key[PF_SK_STACK].port[1] = key[PF_SK_STACK]->port[1];
> + sp->key[PF_SK_STACK].rdomain = htons(key[PF_SK_STACK]->rdomain);
> + sp->key[PF_SK_STACK].af = key[PF_SK_STACK]->af;
> sp->rtableid[PF_SK_WIRE] = htonl(st->rtableid[PF_SK_WIRE]);
> sp->rtableid[PF_SK_STACK] = htonl(st->rtableid[PF_SK_STACK]);
> - sp->proto = st->key[PF_SK_WIRE]->proto;
> - sp->af = st->key[PF_SK_WIRE]->af;
> + sp->proto = key[PF_SK_WIRE]->proto;
> + sp->af = key[PF_SK_WIRE]->af;
>
> /* copy from state */
> strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
> @@ -1255,6 +1275,10 @@ pf_state_export(struct pfsync_state *sp, struct
> pf_state *st)
> sp->set_tos = st->set_tos;
> sp->set_prio[0] = st->set_prio[0];
> sp->set_prio[1] = st->set_prio[1];
> +
> + pf_state_keys_rele(key);
> +
> + return (0);
> }
>
> /* END state table stuff */
> @@ -4108,6 +4132,7 @@ pf_create_state(struct pf_pdesc *pd, struct pf_rule *r,
> struct pf_rule *a,
> * pf_state_inserts() grabs reference for pfsync!
> */
> refcnt_init(&s->refcnt);
> + mtx_init(&s->mtx, IPL_NET);
>
> switch (pd->proto) {
> case IPPROTO_TCP:
> @@ -7789,3 +7814,19 @@ pf_pktenqueue_delayed(void *arg)
>
> pool_put(&pf_pktdelay_pl, pdy);
> }
> +
> +void
> +pf_state_keys_take(struct pf_state *st, struct pf_state_key *keys[])
> +{
> + mtx_enter(&st->mtx);
> + keys[PF_SK_WIRE] = pf_state_key_ref(st->key[PF_SK_WIRE]);
> + keys[PF_SK_STACK] = pf_state_key_ref(st->key[PF_SK_STACK]);
> + mtx_leave(&st->mtx);
> +}
> +
> +void
> +pf_state_keys_rele(struct pf_state_key *keys[])
> +{
> + pf_state_key_unref(keys[PF_SK_WIRE]);
> + pf_state_key_unref(keys[PF_SK_STACK]);
> +}
> diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
> index 93394e6da5c..4604869ede3 100644
> --- a/sys/net/pfvar.h
> +++ b/sys/net/pfvar.h
> @@ -763,6 +763,7 @@ struct pf_state {
> struct pf_sn_head src_nodes;
> struct pf_state_key *key[2]; /* addresses stack and wire */
> struct pfi_kif *kif;
> + struct mutex mtx;
> u_int64_t packets[2];
> u_int64_t bytes[2];
> int32_t creation;
> @@ -1737,7 +1738,7 @@ void
> pf_state_rm_src_node(struct pf_state *,
> extern struct pf_state *pf_find_state_byid(struct pf_state_cmp
> *);
> extern struct pf_state *pf_find_state_all(struct
> pf_state_key_cmp *,
> u_int, int *);
> -extern void pf_state_export(struct pfsync_state *,
> +extern int pf_state_export(struct pfsync_state *,
> struct pf_state *);
> extern void pf_print_state(struct pf_state *);
> extern void pf_print_flags(u_int8_t);
>