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);