aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2015-09-30 14:16:54 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-01 21:24:05 -0400
commit263344e64c0a2ac0e409a1a3f27effb6d57b853e (patch)
tree1383a9017adcfb96767f49cd36f3adfc4357e188
parent77751ee8aec3e1748e0d1471ccbfc008793e88a6 (diff)
bridge: vlan: fix possible null ptr derefs on port init and deinit
When a new port is being added we need to make vlgrp available after rhashtable has been initialized and when removing a port we need to flush the vlans and free the resources after we're sure noone can use the port, i.e. after it's removed from the port list and synchronize_rcu is executed. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_vlan.c16
2 files changed, 12 insertions, 7 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 45e4757c6fd2..934cae9fa317 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -248,7 +248,6 @@ static void del_nbp(struct net_bridge_port *p)
248 248
249 list_del_rcu(&p->list); 249 list_del_rcu(&p->list);
250 250
251 nbp_vlan_flush(p);
252 br_fdb_delete_by_port(br, p, 0, 1); 251 br_fdb_delete_by_port(br, p, 0, 1);
253 nbp_update_port_count(br); 252 nbp_update_port_count(br);
254 253
@@ -257,6 +256,8 @@ static void del_nbp(struct net_bridge_port *p)
257 dev->priv_flags &= ~IFF_BRIDGE_PORT; 256 dev->priv_flags &= ~IFF_BRIDGE_PORT;
258 257
259 netdev_rx_handler_unregister(dev); 258 netdev_rx_handler_unregister(dev);
259 /* use the synchronize_rcu done by netdev_rx_handler_unregister */
260 nbp_vlan_flush(p);
260 261
261 br_multicast_del_port(p); 262 br_multicast_del_port(p);
262 263
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 90ac4b0c55c1..7e9d60a402e2 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -854,16 +854,20 @@ err_rhtbl:
854 854
855int nbp_vlan_init(struct net_bridge_port *p) 855int nbp_vlan_init(struct net_bridge_port *p)
856{ 856{
857 struct net_bridge_vlan_group *vg;
857 int ret = -ENOMEM; 858 int ret = -ENOMEM;
858 859
859 p->vlgrp = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL); 860 vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL);
860 if (!p->vlgrp) 861 if (!vg)
861 goto out; 862 goto out;
862 863
863 ret = rhashtable_init(&p->vlgrp->vlan_hash, &br_vlan_rht_params); 864 ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
864 if (ret) 865 if (ret)
865 goto err_rhtbl; 866 goto err_rhtbl;
866 INIT_LIST_HEAD(&p->vlgrp->vlan_list); 867 INIT_LIST_HEAD(&vg->vlan_list);
868 /* Make sure everything's committed before publishing vg */
869 smp_wmb();
870 p->vlgrp = vg;
867 if (p->br->default_pvid) { 871 if (p->br->default_pvid) {
868 ret = nbp_vlan_add(p, p->br->default_pvid, 872 ret = nbp_vlan_add(p, p->br->default_pvid,
869 BRIDGE_VLAN_INFO_PVID | 873 BRIDGE_VLAN_INFO_PVID |
@@ -875,9 +879,9 @@ out:
875 return ret; 879 return ret;
876 880
877err_vlan_add: 881err_vlan_add:
878 rhashtable_destroy(&p->vlgrp->vlan_hash); 882 rhashtable_destroy(&vg->vlan_hash);
879err_rhtbl: 883err_rhtbl:
880 kfree(p->vlgrp); 884 kfree(vg);
881 885
882 goto out; 886 goto out;
883} 887}