Skip to content

Commit

Permalink
net: dev_addr_list: handle first address in __hw_addr_add_ex
Browse files Browse the repository at this point in the history
struct dev_addr_list is used for device addresses, unicast addresses
and multicast addresses. The first of those needs special handling
of the main address - netdev->dev_addr points directly the data
of the entry and drivers write to it freely, so we can't maintain
it in the rbtree (for now, at least, to be fixed in net-next).

Current work around sprinkles special handling of the first
address on the list throughout the code but it missed the case
where address is being added. First address will not be visible
during subsequent adds.

Syzbot found a warning where unicast addresses are modified
without holding the rtnl lock, tl;dr is that team generates
the same modification multiple times, not necessarily when
right locks are held.

In the repro we have:

  macvlan -> team -> veth

macvlan adds a unicast address to the team. Team then pushes
that address down to its memebers (veths). Next something unrelated
makes team sync member addrs again, and because of the bug
the addr entries get duplicated in the veths. macvlan gets
removed, removes its addr from team which removes only one
of the duplicated addresses from veths. This removal is done
under rtnl. Next syzbot uses iptables to add a multicast addr
to team (which does not hold rtnl lock). Team syncs veth addrs,
but because veths' unicast list still has the duplicate it will
also get sync, even though this update is intended for mc addresses.
Again, uc address updates need rtnl lock, boom.

Reported-by: [email protected]
Fixes: 406f42f ("net-next: When a bond have a massive amount of VLANs with IPv6 addresses, performance of changing link state, attaching a VRF, changing an IPv6 address, etc. go down dramtically.")
Signed-off-by: Jakub Kicinski <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
kuba-moo authored and davem330 committed Sep 30, 2021
1 parent d5ef190 commit a5b8fd6
Showing 1 changed file with 6 additions and 0 deletions.
6 changes: 6 additions & 0 deletions net/core/dev_addr_lists.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
if (addr_len > MAX_ADDR_LEN)
return -EINVAL;

ha = list_first_entry(&list->list, struct netdev_hw_addr, list);
if (ha && !memcmp(addr, ha->addr, addr_len) &&
(!addr_type || addr_type == ha->type))
goto found_it;

while (*ins_point) {
int diff;

Expand All @@ -64,6 +69,7 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
} else if (diff > 0) {
ins_point = &parent->rb_right;
} else {
found_it:
if (exclusive)
return -EEXIST;
if (global) {
Expand Down

0 comments on commit a5b8fd6

Please sign in to comment.