aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2018-08-12 15:04:43 -0400
committerSimon Wunderlich <sw@simonwunderlich.de>2018-09-06 08:37:05 -0400
commit94cb82f594ed86be303398d6dfc7640a6f1d45d4 (patch)
tree9bb9b9401d7a7214dbb0f7fd080ac396d5d50184
parentfa122fec8640eb7186ce5a41b83a4c1744ceef8f (diff)
batman-adv: Prevent duplicated softif_vlan entry
The function batadv_softif_vlan_get is responsible for adding new softif_vlan to the softif_vlan_list. It first checks whether the entry already is in the list or not. If it is, then the creation of a new entry is aborted. But the lock for the list is only held when the list is really modified. This could lead to duplicated entries because another context could create an entry with the same key between the check and the list manipulation. The check and the manipulation of the list must therefore be in the same locked code section. Fixes: 5d2c05b21337 ("batman-adv: add per VLAN interface attribute framework") Signed-off-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
-rw-r--r--net/batman-adv/soft-interface.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 1485263a348b..626ddca332db 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -574,15 +574,20 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
574 struct batadv_softif_vlan *vlan; 574 struct batadv_softif_vlan *vlan;
575 int err; 575 int err;
576 576
577 spin_lock_bh(&bat_priv->softif_vlan_list_lock);
578
577 vlan = batadv_softif_vlan_get(bat_priv, vid); 579 vlan = batadv_softif_vlan_get(bat_priv, vid);
578 if (vlan) { 580 if (vlan) {
579 batadv_softif_vlan_put(vlan); 581 batadv_softif_vlan_put(vlan);
582 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
580 return -EEXIST; 583 return -EEXIST;
581 } 584 }
582 585
583 vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); 586 vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
584 if (!vlan) 587 if (!vlan) {
588 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
585 return -ENOMEM; 589 return -ENOMEM;
590 }
586 591
587 vlan->bat_priv = bat_priv; 592 vlan->bat_priv = bat_priv;
588 vlan->vid = vid; 593 vlan->vid = vid;
@@ -590,17 +595,23 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
590 595
591 atomic_set(&vlan->ap_isolation, 0); 596 atomic_set(&vlan->ap_isolation, 0);
592 597
598 kref_get(&vlan->refcount);
599 hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
600 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
601
602 /* batadv_sysfs_add_vlan cannot be in the spinlock section due to the
603 * sleeping behavior of the sysfs functions and the fs_reclaim lock
604 */
593 err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); 605 err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
594 if (err) { 606 if (err) {
595 kfree(vlan); 607 /* ref for the function */
608 batadv_softif_vlan_put(vlan);
609
610 /* ref for the list */
611 batadv_softif_vlan_put(vlan);
596 return err; 612 return err;
597 } 613 }
598 614
599 spin_lock_bh(&bat_priv->softif_vlan_list_lock);
600 kref_get(&vlan->refcount);
601 hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
602 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
603
604 /* add a new TT local entry. This one will be marked with the NOPURGE 615 /* add a new TT local entry. This one will be marked with the NOPURGE
605 * flag 616 * flag
606 */ 617 */