History

vlan: fix a use-after-free in vlan_device_event()

After refcnt reaches zero, vlan_vid_del() could free dev->vlan_info via RCU: RCU_INIT_POINTER(dev->vlan_info, NULL); call_rcu(&vlan_info->rcu, vlan_info_rcu_free); However, the pointer 'grp' still points to that memory since it is set before vlan_vid_del(): vlan_info = rtnl_dereference(dev->vlan_info); if (!vlan_info) goto out; grp = &vlan_info->grp; Depends on when that RCU callback is scheduled, we could trigger a use-after-free in vlan_group_for_each_dev() right following this vlan_vid_del(). Fix it by moving vlan_vid_del() before setting grp. This is also symmetric to the vlan_vid_add() we call in vlan_device_event().

Cong Wang committed 9 years ago

Commit 052d41c1 parent 2118df91 file · +3 −3Browse files

Unified · Split

net/8021q/vlan.c+3−3
@@ -376,6 +376,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, · 375 unmodified lines
376 dev->name);376 dev->name);
377 vlan_vid_add(dev, htons(ETH_P_8021Q), 0);377 vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
378 }378 }
379 if (event == NETDEV_DOWN &&
380 (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
381 vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
379 382
380 vlan_info = rtnl_dereference(dev->vlan_info);383 vlan_info = rtnl_dereference(dev->vlan_info);
381 if (!vlan_info)384 if (!vlan_info)
@@ -423,9 +426,6 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, · 41 unmodified lines
423 struct net_device *tmp;426 struct net_device *tmp;
424 LIST_HEAD(close_list);427 LIST_HEAD(close_list);
425 428
426 if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
427 vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
428
429 /* Put all VLANs for this dev in the down state too. */429 /* Put all VLANs for this dev in the down state too. */
430 vlan_group_for_each_dev(grp, i, vlandev) {430 vlan_group_for_each_dev(grp, i, vlandev) {
431 flgs = vlandev->flags;431 flgs = vlandev->flags;