Hi, When I tried to add a lock to the inet pcb, I realized that we have to do reference counting. Start with the obvious cases. An inp can be referenced by the PCB queue and hashes, by a pf mbuf header, or by a pf state key.
ok? bluhm Index: kern/uipc_mbuf.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_mbuf.c,v retrieving revision 1.258 diff -u -p -r1.258 uipc_mbuf.c --- kern/uipc_mbuf.c 10 Sep 2018 16:14:07 -0000 1.258 +++ kern/uipc_mbuf.c 12 Sep 2018 16:52:51 -0000 @@ -296,9 +296,9 @@ m_clearhdr(struct mbuf *m) { /* delete all mbuf tags to reset the state */ m_tag_delete_chain(m); - #if NPF > 0 pf_mbuf_unlink_state_key(m); + pf_mbuf_unlink_inpcb(m); #endif /* NPF > 0 */ memset(&m->m_pkthdr, 0, sizeof(m->m_pkthdr)); @@ -430,6 +430,7 @@ m_free(struct mbuf *m) m_tag_delete_chain(m); #if NPF > 0 pf_mbuf_unlink_state_key(m); + pf_mbuf_unlink_inpcb(m); #endif /* NPF > 0 */ } if (m->m_flags & M_EXT) @@ -1350,6 +1351,8 @@ m_dup_pkthdr(struct mbuf *to, struct mbu #if NPF > 0 to->m_pkthdr.pf.statekey = NULL; pf_mbuf_link_state_key(to, from->m_pkthdr.pf.statekey); + to->m_pkthdr.pf.inp = NULL; + pf_mbuf_link_inpcb(to, from->m_pkthdr.pf.inp); #endif /* NPF > 0 */ SLIST_INIT(&to->m_pkthdr.ph_tags); Index: net/pf.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v retrieving revision 1.1074 diff -u -p -r1.1074 pf.c --- net/pf.c 11 Sep 2018 07:53:38 -0000 1.1074 +++ net/pf.c 12 Sep 2018 16:54:13 -0000 @@ -4805,7 +4805,7 @@ pf_test_state(struct pf_pdesc *pd, struc /* XXX make sure it's the same direction ?? */ (*state)->timeout = PFTM_PURGE; *state = NULL; - pd->m->m_pkthdr.pf.inp = inp; + pf_mbuf_link_inpcb(pd->m, inp); return (PF_DROP); } else if (dst->state >= TCPS_ESTABLISHED && src->state >= TCPS_ESTABLISHED) { @@ -7286,7 +7286,7 @@ void pf_pkt_addr_changed(struct mbuf *m) { pf_mbuf_unlink_state_key(m); - m->m_pkthdr.pf.inp = NULL; + pf_mbuf_unlink_inpcb(m); } struct inpcb * @@ -7391,6 +7391,13 @@ pf_state_key_isvalid(struct pf_state_key } void +pf_mbuf_link_state_key(struct mbuf *m, struct pf_state_key *sk) +{ + KASSERT(m->m_pkthdr.pf.statekey == NULL); + m->m_pkthdr.pf.statekey = pf_state_key_ref(sk); +} + +void pf_mbuf_unlink_state_key(struct mbuf *m) { struct pf_state_key *sk = m->m_pkthdr.pf.statekey; @@ -7402,17 +7409,28 @@ pf_mbuf_unlink_state_key(struct mbuf *m) } void -pf_mbuf_link_state_key(struct mbuf *m, struct pf_state_key *sk) +pf_mbuf_link_inpcb(struct mbuf *m, struct inpcb *inp) { - KASSERT(m->m_pkthdr.pf.statekey == NULL); - m->m_pkthdr.pf.statekey = pf_state_key_ref(sk); + KASSERT(m->m_pkthdr.pf.inp == NULL); + m->m_pkthdr.pf.inp = in_pcbref(inp); +} + +void +pf_mbuf_unlink_inpcb(struct mbuf *m) +{ + struct inpcb *inp = m->m_pkthdr.pf.inp; + + if (inp != NULL) { + m->m_pkthdr.pf.inp = NULL; + in_pcbunref(inp); + } } void pf_state_key_link_inpcb(struct pf_state_key *sk, struct inpcb *inp) { KASSERT(sk->inp == NULL); - sk->inp = inp; + sk->inp = in_pcbref(inp); KASSERT(inp->inp_pf_sk == NULL); inp->inp_pf_sk = pf_state_key_ref(sk); } @@ -7427,6 +7445,7 @@ pf_inpcb_unlink_state_key(struct inpcb * sk->inp = NULL; inp->inp_pf_sk = NULL; pf_state_key_unref(sk); + in_pcbunref(inp); } } @@ -7440,6 +7459,7 @@ pf_state_key_unlink_inpcb(struct pf_stat sk->inp = NULL; inp->inp_pf_sk = NULL; pf_state_key_unref(sk); + in_pcbunref(inp); } } Index: net/pfvar.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfvar.h,v retrieving revision 1.485 diff -u -p -r1.485 pfvar.h --- net/pfvar.h 11 Sep 2018 07:53:38 -0000 1.485 +++ net/pfvar.h 12 Sep 2018 16:51:20 -0000 @@ -1961,6 +1961,8 @@ int pf_postprocess_addr(struct pf_sta void pf_mbuf_link_state_key(struct mbuf *, struct pf_state_key *); void pf_mbuf_unlink_state_key(struct mbuf *); +void pf_mbuf_link_inpcb(struct mbuf *, struct inpcb *); +void pf_mbuf_unlink_inpcb(struct mbuf *); u_int8_t* pf_find_tcpopt(u_int8_t *, u_int8_t *, size_t, u_int8_t, u_int8_t); Index: netinet/in_pcb.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.243 diff -u -p -r1.243 in_pcb.c --- netinet/in_pcb.c 11 Sep 2018 14:34:49 -0000 1.243 +++ netinet/in_pcb.c 12 Sep 2018 16:48:32 -0000 @@ -227,6 +227,7 @@ in_pcballoc(struct socket *so, struct in return (ENOBUFS); inp->inp_table = table; inp->inp_socket = so; + refcnt_init(&inp->inp_refcnt); inp->inp_seclevel[SL_AUTH] = IPSEC_AUTH_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_TRANS] = IPSEC_ESP_TRANS_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_NETWORK] = IPSEC_ESP_NETWORK_LEVEL_DEFAULT; @@ -577,7 +578,29 @@ in_pcbdetach(struct inpcb *inp) LIST_REMOVE(inp, inp_hash); TAILQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue); inp->inp_table->inpt_count--; - pool_put(&inpcb_pool, inp); + in_pcbunref(inp); +} + +struct inpcb * +in_pcbref(struct inpcb *inp) +{ + if (inp != NULL) + refcnt_take(&inp->inp_refcnt); + return inp; +} + +void +in_pcbunref(struct inpcb *inp) +{ + if (refcnt_rele(&inp->inp_refcnt)) { + KASSERT((LIST_NEXT(inp, inp_hash) == NULL) || + (LIST_NEXT(inp, inp_hash) == _Q_INVALID)); + KASSERT((LIST_NEXT(inp, inp_lhash) == NULL) || + (LIST_NEXT(inp, inp_lhash) == _Q_INVALID)); + KASSERT((TAILQ_NEXT(inp, inp_queue) == NULL) || + (TAILQ_NEXT(inp, inp_queue) == _Q_INVALID)); + pool_put(&inpcb_pool, inp); + } } void Index: netinet/in_pcb.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.h,v retrieving revision 1.110 diff -u -p -r1.110 in_pcb.h --- netinet/in_pcb.h 11 Sep 2018 14:34:49 -0000 1.110 +++ netinet/in_pcb.h 12 Sep 2018 16:50:32 -0000 @@ -110,6 +110,7 @@ struct inpcb { } inp_ru; #define inp_route inp_ru.ru_route #define inp_route6 inp_ru.ru_route6 + struct refcnt inp_refcnt; /* refcount PCB, delay memory free */ int inp_flags; /* generic IP/datagram flags */ union { /* Header prototype. */ struct ip hu_ip; @@ -260,6 +261,9 @@ int in_pcbaddrisavail(struct inpcb *, s struct proc *); int in_pcbconnect(struct inpcb *, struct mbuf *); void in_pcbdetach(struct inpcb *); +struct inpcb * + in_pcbref(struct inpcb *); +void in_pcbunref(struct inpcb *); void in_pcbdisconnect(struct inpcb *); struct inpcb * in_pcbhashlookup(struct inpcbtable *, struct in_addr, Index: netinet/raw_ip.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.111 diff -u -p -r1.111 raw_ip.c --- netinet/raw_ip.c 5 Jul 2018 21:16:52 -0000 1.111 +++ netinet/raw_ip.c 12 Sep 2018 16:58:55 -0000 @@ -287,7 +287,7 @@ rip_output(struct mbuf *m, struct socket #if NPF > 0 if (inp->inp_socket->so_state & SS_ISCONNECTED && ip->ip_p != IPPROTO_ICMP) - m->m_pkthdr.pf.inp = inp; + pf_mbuf_link_inpcb(m, inp); #endif error = ip_output(m, inp->inp_options, &inp->inp_route, flags, Index: netinet/tcp_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.125 diff -u -p -r1.125 tcp_output.c --- netinet/tcp_output.c 11 Jun 2018 07:40:26 -0000 1.125 +++ netinet/tcp_output.c 12 Sep 2018 17:02:42 -0000 @@ -78,7 +78,11 @@ #include <sys/socketvar.h> #include <sys/kernel.h> +#include <net/if.h> #include <net/route.h> +#if NPF > 0 +#include <net/pfvar.h> +#endif #include <netinet/in.h> #include <netinet/ip.h> @@ -1014,7 +1018,7 @@ send: m->m_pkthdr.ph_rtableid = tp->t_inpcb->inp_rtableid; #if NPF > 0 - m->m_pkthdr.pf.inp = tp->t_inpcb; + pf_mbuf_link_inpcb(m, tp->t_inpcb); #endif switch (tp->pf) { Index: netinet/udp_usrreq.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.250 diff -u -p -r1.250 udp_usrreq.c --- netinet/udp_usrreq.c 5 Jul 2018 21:16:52 -0000 1.250 +++ netinet/udp_usrreq.c 12 Sep 2018 16:59:22 -0000 @@ -998,7 +998,7 @@ udp_output(struct inpcb *inp, struct mbu #if NPF > 0 if (inp->inp_socket->so_state & SS_ISCONNECTED) - m->m_pkthdr.pf.inp = inp; + pf_mbuf_link_inpcb(m, inp); #endif error = ip_output(m, inp->inp_options, &inp->inp_route, Index: netinet6/raw_ip6.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v retrieving revision 1.129 diff -u -p -r1.129 raw_ip6.c --- netinet6/raw_ip6.c 5 Jul 2018 21:16:52 -0000 1.129 +++ netinet6/raw_ip6.c 12 Sep 2018 16:59:32 -0000 @@ -467,7 +467,7 @@ rip6_output(struct mbuf *m, struct socke #if NPF > 0 if (in6p->inp_socket->so_state & SS_ISCONNECTED && so->so_proto->pr_protocol != IPPROTO_ICMPV6) - m->m_pkthdr.pf.inp = in6p; + pf_mbuf_link_inpcb(m, in6p); #endif error = ip6_output(m, optp, &in6p->inp_route6, flags, Index: netinet6/udp6_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/udp6_output.c,v retrieving revision 1.55 diff -u -p -r1.55 udp6_output.c --- netinet6/udp6_output.c 11 Aug 2017 19:53:02 -0000 1.55 +++ netinet6/udp6_output.c 12 Sep 2018 17:03:02 -0000 @@ -74,6 +74,9 @@ #include <net/if.h> #include <net/if_var.h> #include <net/route.h> +#if NPF > 0 +#include <net/pfvar.h> +#endif #include <netinet/in.h> #include <netinet6/in6_var.h> @@ -227,7 +230,7 @@ udp6_output(struct inpcb *in6p, struct m #if NPF > 0 if (in6p->inp_socket->so_state & SS_ISCONNECTED) - m->m_pkthdr.pf.inp = in6p; + pf_mbuf_link_inpcb(m, in6p); #endif error = ip6_output(m, optp, &in6p->inp_route6,