Hi,

When creating, changing and destroying vlan interfaces multiple
times, root can crash the OpenBSD 5.8 kernel with ifconfig.

The code in -current has been implemented differently, so this fix
only applies to 5.8.  As I cannot test it with -current machines,
could someone with OpenBSD 5.8 and some funky vlan configuration
run this diff?  When I get enough positive reports, I will commit
to 5.8-stable.  5.7 is not affected.

bluhm

Index: net/if_vlan.c
===================================================================
RCS file: /mount/cvsdev/cvs/openbsd/src/sys/net/if_vlan.c,v
retrieving revision 1.135
diff -u -p -r1.135 if_vlan.c
--- net/if_vlan.c       20 Jul 2015 22:16:41 -0000      1.135
+++ net/if_vlan.c       11 Jan 2016 17:34:19 -0000
@@ -347,6 +347,7 @@ vlan_input(struct ifnet *ifp, struct mbu
 int
 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
 {
+       struct ifih             *vlan_ifih;
        struct sockaddr_dl      *sdl1, *sdl2;
        struct vlan_taghash     *tagh;
        u_int                    flags;
@@ -358,15 +359,17 @@ vlan_config(struct ifvlan *ifv, struct i
                return (0);
 
        /* Can we share an ifih between multiple vlan(4) instances? */
-       ifv->ifv_ifih = SLIST_FIRST(&p->if_inputs);
-       if (ifv->ifv_ifih->ifih_input != vlan_input) {
-               ifv->ifv_ifih = malloc(sizeof(*ifv->ifv_ifih), M_DEVBUF,
+       vlan_ifih = SLIST_FIRST(&p->if_inputs);
+       if (vlan_ifih->ifih_input != vlan_input) {
+               vlan_ifih = malloc(sizeof(*vlan_ifih), M_DEVBUF,
                    M_NOWAIT);
-               if (ifv->ifv_ifih == NULL)
+               if (vlan_ifih == NULL)
                        return (ENOMEM);
-               ifv->ifv_ifih->ifih_input = vlan_input;
-               ifv->ifv_ifih->ifih_refcnt = 0;
+               vlan_ifih->ifih_input = vlan_input;
+               vlan_ifih->ifih_refcnt = 0;
        }
+       /* Do no free our reference during vlan_unconfig() */
+       ++vlan_ifih->ifih_refcnt;
 
        /* Remember existing interface flags and reset the interface */
        flags = ifv->ifv_flags;
@@ -437,8 +440,9 @@ vlan_config(struct ifvlan *ifv, struct i
 
        s = splnet();
        /* Change input handler of the physical interface. */
-       if (++ifv->ifv_ifih->ifih_refcnt == 1)
-               SLIST_INSERT_HEAD(&p->if_inputs, ifv->ifv_ifih, ifih_next);
+       ifv->ifv_ifih = vlan_ifih;
+       if (vlan_ifih->ifih_refcnt == 1)
+               SLIST_INSERT_HEAD(&p->if_inputs, vlan_ifih, ifih_next);
 
        LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
        splx(s);

Reply via email to