Fix a double free in the destroy path triggered when a second process,
authormpi <mpi@openbsd.org>
Mon, 15 Jun 2015 15:55:08 +0000 (15:55 +0000)
committermpi <mpi@openbsd.org>
Mon, 15 Jun 2015 15:55:08 +0000 (15:55 +0000)
in my case dhclient(8), races with ifconfig(8) to free the descriptors
of the joined multicast groups.

While here reduce the difference with carp(4).

ok dms@

sys/net/if_trunk.c

index 32d23f2..5de66dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_trunk.c,v 1.101 2015/06/09 14:50:14 mpi Exp $      */
+/*     $OpenBSD: if_trunk.c,v 1.102 2015/06/15 15:55:08 mpi Exp $      */
 
 /*
  * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
@@ -857,18 +857,20 @@ trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr)
        if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET)
                return (error);
 
-       if ((error = trunk_ioctl_allports(tr, SIOCDELMULTI,
-           (caddr_t)ifr)) != 0) {
+       /* We no longer use this multicast address.  Tell parent so. */
+       error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
+       if (error == 0) {
+               SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
+               free(mc, M_DEVBUF, sizeof(*mc));
+       } else {
                /* XXX At least one port failed to remove the address */
                if (tr->tr_ifflags & IFF_DEBUG) {
                        printf("%s: failed to remove multicast address "
-                           "on all ports\n", tr->tr_ifname);
+                           "on all ports (%d)\n", tr->tr_ifname, error);
                }
+               (void)ether_addmulti(ifr, &tr->tr_ac);
        }
 
-       SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
-       free(mc, M_DEVBUF, 0);
-
        return (0);
 }
 
@@ -886,7 +888,7 @@ trunk_ether_purgemulti(struct trunk_softc *tr)
                trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
 
                SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
-               free(mc, M_DEVBUF, 0);
+               free(mc, M_DEVBUF, sizeof(*mc));
        }
 }