Re: pfsync if_get conversion
On Thu, Mar 09, 2017 at 12:42:43PM +0100, Martin Pieuchot wrote: > On 09/03/17(Thu) 08:48, Stefan Sperling wrote: > > This diff converts a struct ifnet pointer in pfsync's softc into an > > ifindex with corresponding if_get()/if_put() calls. > > This avoid the panic but obfuscate the problem. What you want is a > detachhook such that if the parent interface is destroyed you don't > leave a sale pointer. > > You can look at how vlan(4) or other pseudo drivers do it. Right. The diff below fixes the issue, too. vlan(4) uses both a detachhook and if_get/if_put. Fixing the crash is important so I would commit this fix separately first. I could later redo my if_get/if_put diff on top unless that is not wanted. Index: if_pfsync.c === RCS file: /cvs/src/sys/net/if_pfsync.c,v retrieving revision 1.245 diff -u -p -r1.245 if_pfsync.c --- if_pfsync.c 20 Feb 2017 06:30:39 - 1.245 +++ if_pfsync.c 10 Mar 2017 08:58:18 - @@ -234,6 +234,7 @@ struct pfsync_softc { TAILQ_HEAD(, tdb)sc_tdb_q; void*sc_lhcookie; + void*sc_dhcookie; struct timeout sc_tmo; }; @@ -252,6 +253,7 @@ int pfsyncoutput(struct ifnet *, struct intpfsyncioctl(struct ifnet *, u_long, caddr_t); void pfsyncstart(struct ifnet *); void pfsync_syncdev_state(void *); +void pfsync_ifdetach(void *); void pfsync_deferred(struct pf_state *, int); void pfsync_undefer(struct pfsync_deferral *, int); @@ -365,10 +367,13 @@ pfsync_clone_destroy(struct ifnet *ifp) if (sc->sc_link_demoted) carp_group_demote_adj(>sc_if, -1, "pfsync destroy"); #endif - if (sc->sc_sync_if) + if (sc->sc_sync_if) { hook_disestablish( sc->sc_sync_if->if_linkstatehooks, sc->sc_lhcookie); + hook_disestablish(sc->sc_sync_if->if_detachhooks, + sc->sc_dhcookie);; + } if_detach(ifp); pfsync_drop(sc); @@ -427,6 +432,14 @@ pfsync_syncdev_state(void *arg) } } +void +pfsync_ifdetach(void *arg) +{ + struct pfsync_softc *sc = arg; + + sc->sc_sync_if = NULL; +} + int pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, struct pf_state_peer *d) @@ -1313,10 +1326,14 @@ pfsyncioctl(struct ifnet *ifp, u_long cm sc->sc_defer = pfsyncr.pfsyncr_defer; if (pfsyncr.pfsyncr_syncdev[0] == 0) { - if (sc->sc_sync_if) + if (sc->sc_sync_if) { hook_disestablish( sc->sc_sync_if->if_linkstatehooks, sc->sc_lhcookie); + hook_disestablish( + sc->sc_sync_if->if_detachhooks, + sc->sc_dhcookie);; + } sc->sc_sync_if = NULL; if (imo->imo_num_memberships > 0) { in_delmulti(imo->imo_membership[ @@ -1338,10 +1355,14 @@ pfsyncioctl(struct ifnet *ifp, u_long cm sifp->if_mtu < MCLBYTES - sizeof(struct ip)) pfsync_sendout(); - if (sc->sc_sync_if) + if (sc->sc_sync_if) { hook_disestablish( sc->sc_sync_if->if_linkstatehooks, sc->sc_lhcookie); + hook_disestablish( + sc->sc_sync_if->if_detachhooks, + sc->sc_dhcookie);; + } sc->sc_sync_if = sifp; if (imo->imo_num_memberships > 0) { @@ -1388,6 +1409,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cm sc->sc_lhcookie = hook_establish(sc->sc_sync_if->if_linkstatehooks, 1, pfsync_syncdev_state, sc); + sc->sc_dhcookie = hook_establish(sc->sc_sync_if->if_detachhooks, + 0, pfsync_ifdetach, sc); pfsync_request_full_update(sc); splx(s);
Re: pfsync if_get conversion
On 09/03/17(Thu) 08:48, Stefan Sperling wrote: > This diff converts a struct ifnet pointer in pfsync's softc into an > ifindex with corresponding if_get()/if_put() calls. This avoid the panic but obfuscate the problem. What you want is a detachhook such that if the parent interface is destroyed you don't leave a sale pointer. You can look at how vlan(4) or other pseudo drivers do it.
pfsync if_get conversion
This diff converts a struct ifnet pointer in pfsync's softc into an ifindex with corresponding if_get()/if_put() calls. Seems to still work fine and fixes the following panic reported by double-p: ifconfig pfsync0 syncdev vlan5 up ifconfig vlan5 destroy ifconfig pfsync0 destroy -> crash because of stale pointer sc->sc_sync_if ddb> trace hook_disestablish() at hook_disestablish+0x25 pfsync_clone_destroy() at pfsync_clone_destroy+0x85 ifioctl() at ifioctl+0x232 sys_ioctl() at sys_ioctl+0x196 syscall() at syscall+0x19b --- syscall (number 54) --- end of kernel end trace frame Index: if_pfsync.c === RCS file: /cvs/src/sys/net/if_pfsync.c,v retrieving revision 1.245 diff -u -p -r1.245 if_pfsync.c --- if_pfsync.c 20 Feb 2017 06:30:39 - 1.245 +++ if_pfsync.c 9 Mar 2017 06:55:28 - @@ -196,7 +196,7 @@ voidpfsync_out_tdb(struct tdb *, void * struct pfsync_softc { struct ifnet sc_if; - struct ifnet*sc_sync_if; + int sc_syncdev_ifidx; struct pool sc_pool; @@ -355,6 +355,7 @@ pfsync_clone_destroy(struct ifnet *ifp) { struct pfsync_softc *sc = ifp->if_softc; struct pfsync_deferral *pd; + struct ifnet *syncdev; timeout_del(>sc_bulkfail_tmo); timeout_del(>sc_bulk_tmo); @@ -365,10 +366,13 @@ pfsync_clone_destroy(struct ifnet *ifp) if (sc->sc_link_demoted) carp_group_demote_adj(>sc_if, -1, "pfsync destroy"); #endif - if (sc->sc_sync_if) + syncdev = if_get(sc->sc_syncdev_ifidx); + if (syncdev) { hook_disestablish( - sc->sc_sync_if->if_linkstatehooks, + syncdev->if_linkstatehooks, sc->sc_lhcookie); + if_put(syncdev); + } if_detach(ifp); pfsync_drop(sc); @@ -401,11 +405,15 @@ void pfsync_syncdev_state(void *arg) { struct pfsync_softc *sc = arg; + struct ifnet *syncdev; - if (!sc->sc_sync_if || !(sc->sc_if.if_flags & IFF_UP)) + syncdev = if_get(sc->sc_syncdev_ifidx); + if (!syncdev || !(sc->sc_if.if_flags & IFF_UP)) { + if_put(syncdev); return; + } - if (sc->sc_sync_if->if_link_state == LINK_STATE_DOWN) { + if (syncdev->if_link_state == LINK_STATE_DOWN) { sc->sc_if.if_flags &= ~IFF_RUNNING; if (!sc->sc_link_demoted) { #if NCARP > 0 @@ -425,6 +433,8 @@ pfsync_syncdev_state(void *arg) pfsync_request_full_update(sc); } + + if_put(syncdev); } int @@ -640,6 +650,7 @@ pfsync_input(struct mbuf **mp, int *offp { struct mbuf *n, *m = *mp; struct pfsync_softc *sc = pfsyncif; + struct ifnet *syncdev; struct ip *ip = mtod(m, struct ip *); struct pfsync_header *ph; struct pfsync_subheader subh; @@ -649,11 +660,14 @@ pfsync_input(struct mbuf **mp, int *offp /* verify that we have a sync interface configured */ if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING) || - sc->sc_sync_if == NULL || !pf_status.running) + !pf_status.running) + goto done; + syncdev = if_get(sc->sc_syncdev_ifidx); + if (syncdev == NULL) goto done; /* verify that the packet came in on the right interface */ - if (sc->sc_sync_if->if_index != m->m_pkthdr.ph_ifidx) { + if (sc->sc_syncdev_ifidx != m->m_pkthdr.ph_ifidx) { pfsyncstat_inc(pfsyncs_badif); goto done; } @@ -729,6 +743,7 @@ pfsync_input(struct mbuf **mp, int *offp done: m_freem(m); + if_put(syncdev); return IPPROTO_DONE; } @@ -1234,7 +1249,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cm struct ifreq *ifr = (struct ifreq *)data; struct ip_moptions *imo = >sc_imo; struct pfsyncreq pfsyncr; - struct ifnet*sifp; + struct ifnet*sifp, *syncdev = NULL; struct ip *ip; int s, error; @@ -1269,10 +1284,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cm splx(s); break; case SIOCSIFMTU: - if (!sc->sc_sync_if || + syncdev = if_get(sc->sc_syncdev_ifidx); + if (!syncdev || ifr->ifr_mtu <= PFSYNC_MINPKT || - ifr->ifr_mtu > sc->sc_sync_if->if_mtu) + ifr->ifr_mtu > syncdev->if_mtu) { + if_put(syncdev); return (EINVAL); + } s = splnet(); if (ifr->ifr_mtu < ifp->if_mtu) pfsync_sendout(); @@ -1281,9 +1299,11 @@ pfsyncioctl(struct ifnet *ifp, u_long cm break; case SIOCGETPFSYNC: bzero(, sizeof(pfsyncr)); - if (sc->sc_sync_if) { -