Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 454594f3 authored by Linus Lüssing's avatar Linus Lüssing Committed by David S. Miller
Browse files

Revert "bridge: only expire the mdb entry when query is received"



While this commit was a good attempt to fix issues occuring when no
multicast querier is present, this commit still has two more issues:

1) There are cases where mdb entries do not expire even if there is a
querier present. The bridge will unnecessarily continue flooding
multicast packets on the according ports.

2) Never removing an mdb entry could be exploited for a Denial of
Service by an attacker on the local link, slowly, but steadily eating up
all memory.

Actually, this commit became obsolete with
"bridge: disable snooping if there is no querier" (b00589af)
which included fixes for a few more cases.

Therefore reverting the following commits (the commit stated in the
commit message plus three of its follow up fixes):

====================
Revert "bridge: update mdb expiration timer upon reports."
This reverts commit f144febd.
Revert "bridge: do not call setup_timer() multiple times"
This reverts commit 1faabf2a.
Revert "bridge: fix some kernel warning in multicast timer"
This reverts commit c7e8e8a8.
Revert "bridge: only expire the mdb entry when query is received"
This reverts commit 9f00b2e7.
====================

CC: Cong Wang <amwang@redhat.com>
Signed-off-by: default avatarLinus Lüssing <linus.luessing@web.de>
Reviewed-by: default avatarVlad Yasevich <vyasevich@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 02cf4ebd
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
		call_rcu_bh(&p->rcu, br_multicast_free_pg);
		call_rcu_bh(&p->rcu, br_multicast_free_pg);
		err = 0;
		err = 0;


		if (!mp->ports && !mp->mglist && mp->timer_armed &&
		if (!mp->ports && !mp->mglist &&
		    netif_running(br->dev))
		    netif_running(br->dev))
			mod_timer(&mp->timer, jiffies);
			mod_timer(&mp->timer, jiffies);
		break;
		break;
+27 −20
Original line number Original line Diff line number Diff line
@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
		del_timer(&p->timer);
		del_timer(&p->timer);
		call_rcu_bh(&p->rcu, br_multicast_free_pg);
		call_rcu_bh(&p->rcu, br_multicast_free_pg);


		if (!mp->ports && !mp->mglist && mp->timer_armed &&
		if (!mp->ports && !mp->mglist &&
		    netif_running(br->dev))
		    netif_running(br->dev))
			mod_timer(&mp->timer, jiffies);
			mod_timer(&mp->timer, jiffies);


@@ -611,9 +611,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
		break;
		break;


	default:
	default:
		/* If we have an existing entry, update it's expire timer */
		mod_timer(&mp->timer,
			  jiffies + br->multicast_membership_interval);
		goto out;
		goto out;
	}
	}


@@ -623,7 +620,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,


	mp->br = br;
	mp->br = br;
	mp->addr = *group;
	mp->addr = *group;

	setup_timer(&mp->timer, br_multicast_group_expired,
	setup_timer(&mp->timer, br_multicast_group_expired,
		    (unsigned long)mp);
		    (unsigned long)mp);


@@ -663,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br,
	struct net_bridge_mdb_entry *mp;
	struct net_bridge_mdb_entry *mp;
	struct net_bridge_port_group *p;
	struct net_bridge_port_group *p;
	struct net_bridge_port_group __rcu **pp;
	struct net_bridge_port_group __rcu **pp;
	unsigned long now = jiffies;
	int err;
	int err;


	spin_lock(&br->multicast_lock);
	spin_lock(&br->multicast_lock);
@@ -677,18 +674,15 @@ static int br_multicast_add_group(struct net_bridge *br,


	if (!port) {
	if (!port) {
		mp->mglist = true;
		mp->mglist = true;
		mod_timer(&mp->timer, now + br->multicast_membership_interval);
		goto out;
		goto out;
	}
	}


	for (pp = &mp->ports;
	for (pp = &mp->ports;
	     (p = mlock_dereference(*pp, br)) != NULL;
	     (p = mlock_dereference(*pp, br)) != NULL;
	     pp = &p->next) {
	     pp = &p->next) {
		if (p->port == port) {
		if (p->port == port)
			/* We already have a portgroup, update the timer.  */
			goto found;
			mod_timer(&p->timer,
				  jiffies + br->multicast_membership_interval);
			goto out;
		}
		if ((unsigned long)p->port < (unsigned long)port)
		if ((unsigned long)p->port < (unsigned long)port)
			break;
			break;
	}
	}
@@ -699,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br,
	rcu_assign_pointer(*pp, p);
	rcu_assign_pointer(*pp, p);
	br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
	br_mdb_notify(br->dev, port, group, RTM_NEWMDB);


found:
	mod_timer(&p->timer, now + br->multicast_membership_interval);
out:
out:
	err = 0;
	err = 0;


@@ -1198,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
	if (!mp)
	if (!mp)
		goto out;
		goto out;


	mod_timer(&mp->timer, now + br->multicast_membership_interval);
	mp->timer_armed = true;

	max_delay *= br->multicast_last_member_count;
	max_delay *= br->multicast_last_member_count;


	if (mp->mglist &&
	if (mp->mglist &&
@@ -1277,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
	if (!mp)
	if (!mp)
		goto out;
		goto out;


	mod_timer(&mp->timer, now + br->multicast_membership_interval);
	mp->timer_armed = true;

	max_delay *= br->multicast_last_member_count;
	max_delay *= br->multicast_last_member_count;
	if (mp->mglist &&
	if (mp->mglist &&
	    (timer_pending(&mp->timer) ?
	    (timer_pending(&mp->timer) ?
@@ -1365,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
			call_rcu_bh(&p->rcu, br_multicast_free_pg);
			call_rcu_bh(&p->rcu, br_multicast_free_pg);
			br_mdb_notify(br->dev, port, group, RTM_DELMDB);
			br_mdb_notify(br->dev, port, group, RTM_DELMDB);


			if (!mp->ports && !mp->mglist && mp->timer_armed &&
			if (!mp->ports && !mp->mglist &&
			    netif_running(br->dev))
			    netif_running(br->dev))
				mod_timer(&mp->timer, jiffies);
				mod_timer(&mp->timer, jiffies);
		}
		}
@@ -1377,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br,
		     br->multicast_last_member_interval;
		     br->multicast_last_member_interval;


	if (!port) {
	if (!port) {
		if (mp->mglist && mp->timer_armed &&
		if (mp->mglist &&
		    (timer_pending(&mp->timer) ?
		    (timer_pending(&mp->timer) ?
		     time_after(mp->timer.expires, time) :
		     time_after(mp->timer.expires, time) :
		     try_to_del_timer_sync(&mp->timer) >= 0)) {
		     try_to_del_timer_sync(&mp->timer) >= 0)) {
			mod_timer(&mp->timer, time);
			mod_timer(&mp->timer, time);
		}
		}

		goto out;
	}

	for (p = mlock_dereference(mp->ports, br);
	     p != NULL;
	     p = mlock_dereference(p->next, br)) {
		if (p->port != port)
			continue;

		if (!hlist_unhashed(&p->mglist) &&
		    (timer_pending(&p->timer) ?
		     time_after(p->timer.expires, time) :
		     try_to_del_timer_sync(&p->timer) >= 0)) {
			mod_timer(&p->timer, time);
		}

		break;
	}
	}
out:
out:
	spin_unlock(&br->multicast_lock);
	spin_unlock(&br->multicast_lock);
@@ -1805,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br)
		hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
		hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
					  hlist[ver]) {
					  hlist[ver]) {
			del_timer(&mp->timer);
			del_timer(&mp->timer);
			mp->timer_armed = false;
			call_rcu_bh(&mp->rcu, br_multicast_free_group);
			call_rcu_bh(&mp->rcu, br_multicast_free_group);
		}
		}
	}
	}
+0 −1
Original line number Original line Diff line number Diff line
@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry
	struct timer_list		timer;
	struct timer_list		timer;
	struct br_ip			addr;
	struct br_ip			addr;
	bool				mglist;
	bool				mglist;
	bool				timer_armed;
};
};


struct net_bridge_mdb_htable
struct net_bridge_mdb_htable