summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkp <kp@FreeBSD.org>2015-07-01 21:21:14 +0000
committerkp <kp@FreeBSD.org>2015-07-01 21:21:14 +0000
commitf1fbe0ce5b7e8c86d845fa9ac8d872fe69a92b28 (patch)
tree178c1feb7e63e73dbf6ce8d034c211ad111f02f5
parentb3962232547830a914bb0eb30f16da744b17ad73 (diff)
downloadFreeBSD-src-f1fbe0ce5b7e8c86d845fa9ac8d872fe69a92b28.zip
FreeBSD-src-f1fbe0ce5b7e8c86d845fa9ac8d872fe69a92b28.tar.gz
MFC r284348: Fix panic when adding vtnet interfaces to a bridge
vtnet interfaces are always in promiscuous mode (at least if the VIRTIO_NET_F_CTRL_RX feature is not negotiated with the host). if_promisc() on a vtnet interface returned ENOTSUP although it has IFF_PROMISC set. This confused the bridge code. Instead we now accept all enable/disable promiscuous commands (and always keep IFF_PROMISC set). There are also two issues with the if_bridge error handling. If if_promisc() fails it uses bridge_delete_member() to clean up. This tries to disable promiscuous mode on the interface. That runs into an assert, because promiscuous mode was never set in the first place. (That's the panic reported in PR 200210.) We can only unset promiscuous mode if the interface actually is promiscuous. This goes against the reference counting done by if_promisc(), but only the first/last if_promic() calls can actually fail, so this is safe. A second issue is a double free of bif. It's already freed by bridge_delete_member(). PR: 200210
-rw-r--r--sys/dev/virtio/network/if_vtnet.c8
-rw-r--r--sys/net/if_bridge.c11
2 files changed, 12 insertions, 7 deletions
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 8e8c8d7..5453998 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -1078,8 +1078,12 @@ vtnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
(IFF_PROMISC | IFF_ALLMULTI)) {
if (sc->vtnet_flags & VTNET_FLAG_CTRL_RX)
vtnet_rx_filter(sc);
- else
- error = ENOTSUP;
+ else {
+ ifp->if_flags |= IFF_PROMISC;
+ if ((ifp->if_flags ^ sc->vtnet_if_flags)
+ & IFF_ALLMULTI)
+ error = ENOTSUP;
+ }
}
} else
vtnet_init_locked(sc);
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 572ee06..f7c6365 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -984,9 +984,12 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
case IFT_ETHER:
case IFT_L2VLAN:
/*
- * Take the interface out of promiscuous mode.
+ * Take the interface out of promiscuous mode, but only
+ * if it was promiscuous in the first place. It might
+ * not be if we're in the bridge_ioctl_add() error path.
*/
- (void) ifpromisc(ifs, 0);
+ if (ifs->if_flags & IFF_PROMISC)
+ (void) ifpromisc(ifs, 0);
break;
case IFT_GIF:
@@ -1154,10 +1157,8 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
break;
}
- if (error) {
+ if (error)
bridge_delete_member(sc, bif, 0);
- free(bif, M_DEVBUF);
- }
return (error);
}
OpenPOWER on IntegriCloud