Re: pfsync if_get conversion

2017-03-10 Thread Stefan Sperling
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

2017-03-09 Thread Martin Pieuchot
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

2017-03-08 Thread Stefan Sperling
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) {
-