diff mbox

[OpenWrt-Devel] kernel: bridge: multicast: backport a few more fixes for 3.10

Message ID 1419909056-7614-1-git-send-email-linus.luessing@c0d3.blue
State Accepted
Headers show

Commit Message

Linus Lüssing Dec. 30, 2014, 3:10 a.m. UTC
The following patches unfortunately didn't hit the kernel stable
branches yet, therefore cherrypicking them for OpenWRT here:

* bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
* bridge: multicast: enable snooping on general queries only
* bridge: multicast: add sanity check for general query destination

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 .../patches-3.10/070-net_bridge_backports.patch    |  193 ++++++++++++++++----
 .../644-bridge_optimize_netfilter_hooks.patch      |    6 +-
 2 files changed, 162 insertions(+), 37 deletions(-)

Comments

Linus Lüssing Jan. 13, 2015, 11:12 p.m. UTC | #1
On Tue, Dec 30, 2014 at 04:10:56AM +0100, Linus Lüssing wrote:
> The following patches unfortunately didn't hit the kernel stable
> branches yet, therefore cherrypicking them for OpenWRT here:
> 
> * bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
> * bridge: multicast: enable snooping on general queries only
> * bridge: multicast: add sanity check for general query destination
> 
> Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
> ---
>  .../patches-3.10/070-net_bridge_backports.patch    |  193 ++++++++++++++++----
>  .../644-bridge_optimize_netfilter_hooks.patch      |    6 +-
>  2 files changed, 162 insertions(+), 37 deletions(-)
> 

Bump
Linus Lüssing Jan. 18, 2015, 11:26 p.m. UTC | #2
On Wed, Jan 14, 2015 at 12:12:33AM +0100, Linus Lüssing wrote:
> On Tue, Dec 30, 2014 at 04:10:56AM +0100, Linus Lüssing wrote:
> > The following patches unfortunately didn't hit the kernel stable
> > branches yet, therefore cherrypicking them for OpenWRT here:
> > 
> > * bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
> > * bridge: multicast: enable snooping on general queries only
> > * bridge: multicast: add sanity check for general query destination
> > 
> > Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
> > ---
> >  .../patches-3.10/070-net_bridge_backports.patch    |  193 ++++++++++++++++----
> >  .../644-bridge_optimize_netfilter_hooks.patch      |    6 +-
> >  2 files changed, 162 insertions(+), 37 deletions(-)
> > 
> 
> Bump

Didn't notice that this patch got applied to trunk already, just
saw it while browsing the dev.openwrt.org. Thanks!

Would it be possible to apply it to Barrier Breaker, too? The
patch only contains fixes and the issues are still present in BB,
too.

Thanks!

Cheers, Linus
Felix Fietkau Jan. 19, 2015, 1:16 a.m. UTC | #3
On 2015-01-19 00:26, Linus Lüssing wrote:
> On Wed, Jan 14, 2015 at 12:12:33AM +0100, Linus Lüssing wrote:
>> On Tue, Dec 30, 2014 at 04:10:56AM +0100, Linus Lüssing wrote:
>> > The following patches unfortunately didn't hit the kernel stable
>> > branches yet, therefore cherrypicking them for OpenWRT here:
>> > 
>> > * bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
>> > * bridge: multicast: enable snooping on general queries only
>> > * bridge: multicast: add sanity check for general query destination
>> > 
>> > Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
>> > ---
>> >  .../patches-3.10/070-net_bridge_backports.patch    |  193 ++++++++++++++++----
>> >  .../644-bridge_optimize_netfilter_hooks.patch      |    6 +-
>> >  2 files changed, 162 insertions(+), 37 deletions(-)
>> > 
>> 
>> Bump
> 
> Didn't notice that this patch got applied to trunk already, just
> saw it while browsing the dev.openwrt.org. Thanks!
> 
> Would it be possible to apply it to Barrier Breaker, too? The
> patch only contains fixes and the issues are still present in BB,
> too.
Backported in r44049

- Felix
diff mbox

Patch

diff --git a/target/linux/generic/patches-3.10/070-net_bridge_backports.patch b/target/linux/generic/patches-3.10/070-net_bridge_backports.patch
index f303c3a..48d6eda 100644
--- a/target/linux/generic/patches-3.10/070-net_bridge_backports.patch
+++ b/target/linux/generic/patches-3.10/070-net_bridge_backports.patch
@@ -1,3 +1,88 @@ 
+commit f0b4eeced518c632210ef2aea44fc92cc9e86cce
+Author: Linus Lüssing <linus.luessing@web.de>
+Date:   Mon Nov 17 12:20:28 2014 +0100
+
+    bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
+
+    Ebtables on the OUTPUT chain (NF_BR_LOCAL_OUT) would not work as expected
+    for both locally generated IGMP and MLD queries. The IP header specific
+    filter options are off by 14 Bytes for netfilter (actual output on
+    interfaces is fine).
+
+    NF_HOOK() expects the skb->data to point to the IP header, not the
+    ethernet one (while dev_queue_xmit() does not). Luckily there is an
+    br_dev_queue_push_xmit() helper function already - let's just use that.
+
+    Introduced by eb1d16414339a6e113d89e2cca2556005d7ce919
+    ("bridge: Add core IGMP snooping support")
+
+    Ebtables example:
+
+    $ ebtables -I OUTPUT -p IPv6 -o eth1 --logical-out br0 \
+        --log --log-level 6 --log-ip6 --log-prefix="~EBT: " -j DROP
+
+    before (broken):
+
+    ~EBT:  IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
+        MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
+        SRC=64a4:39c2:86dd:6000:0000:0020:0001:fe80 IPv6 \
+        DST=0000:0000:0000:0004:64ff:fea4:39c2:ff02, \
+        IPv6 priority=0x3, Next Header=2
+
+    after (working):
+
+    ~EBT:  IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
+       MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
+        SRC=fe80:0000:0000:0000:0004:64ff:fea4:39c2 IPv6 \
+        DST=ff02:0000:0000:0000:0000:0000:0000:0001, \
+        IPv6 priority=0x0, Next Header=0
+
+    Signed-off-by: Linus Lüssing <linus.luessing@web.de>
+    Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
+    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 20a599bec95a52fa72432b2376a2ce47c5bb68fb
+Author: Linus Lüssing <linus.luessing@web.de>
+Date:   Mon Mar 10 22:25:25 2014 +0100
+
+    bridge: multicast: enable snooping on general queries only
+
+    Without this check someone could easily create a denial of service
+    by injecting multicast-specific queries to enable the bridge
+    snooping part if no real querier issuing periodic general queries
+    is present on the link which would result in the bridge wrongly
+    shutting down ports for multicast traffic as the bridge did not learn
+    about these listeners.
+
+    With this patch the snooping code is enabled upon receiving valid,
+    general queries only.
+
+    Signed-off-by: Linus Lüssing <linus.luessing@web.de>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 9ed973cc40c588abeaa58aea0683ea665132d11d
+Author: Linus Lüssing <linus.luessing@web.de>
+Date:   Mon Mar 10 22:25:24 2014 +0100
+
+    bridge: multicast: add sanity check for general query destination
+
+    General IGMP and MLD queries are supposed to have the multicast
+    link-local all-nodes address as their destination according to RFC2236
+    section 9, RFC3376 section 4.1.12/9.1, RFC2710 section 8 and RFC3810
+    section 5.1.15.
+
+    Without this check, such malformed IGMP/MLD queries can result in a
+    denial of service: The queries are ignored by most IGMP/MLD listeners
+    therefore they will not respond with an IGMP/MLD report. However,
+    without this patch these malformed MLD queries would enable the
+    snooping part in the bridge code, potentially shutting down the
+    according ports towards these hosts for multicast traffic as the
+    bridge did not learn about these listeners.
+
+    Reported-by: Jan Stancek <jstancek@redhat.com>
+    Signed-off-by: Linus Lüssing <linus.luessing@web.de>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
 commit 3c3769e63301fd92fcaf51870c371583dd0282ce
 Author: Linus Lüssing <linus.luessing@web.de>
 Date:   Wed Sep 4 02:13:39 2013 +0200
@@ -229,7 +314,17 @@  Date:   Tue May 21 21:52:54 2013 +0000
  static void __br_multicast_send_query(struct net_bridge *br,
  				      struct net_bridge_port *port,
  				      struct br_ip *ip)
-@@ -790,37 +809,45 @@ static void __br_multicast_send_query(st
+@@ -781,46 +800,53 @@ static void __br_multicast_send_query(st
+ 		return;
+ 
+ 	if (port) {
+-		__skb_push(skb, sizeof(struct ethhdr));
+ 		skb->dev = port->dev;
+ 		NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+-			dev_queue_xmit);
++			br_dev_queue_push_xmit);
+ 	} else
+ 		netif_rx(skb);
  }
  
  static void br_multicast_send_query(struct net_bridge *br,
@@ -288,7 +383,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	struct net_bridge *br = port->br;
  
  	spin_lock(&br->multicast_lock);
-@@ -828,25 +855,43 @@ static void br_multicast_port_query_expi
+@@ -828,25 +854,43 @@ static void br_multicast_port_query_expi
  	    port->state == BR_STATE_BLOCKING)
  		goto out;
  
@@ -339,7 +434,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  }
  
  void br_multicast_del_port(struct net_bridge_port *port)
-@@ -854,13 +899,13 @@ void br_multicast_del_port(struct net_br
+@@ -854,13 +898,13 @@ void br_multicast_del_port(struct net_br
  	del_timer_sync(&port->multicast_router_timer);
  }
  
@@ -358,7 +453,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  }
  
  void br_multicast_enable_port(struct net_bridge_port *port)
-@@ -871,7 +916,10 @@ void br_multicast_enable_port(struct net
+@@ -871,7 +915,10 @@ void br_multicast_enable_port(struct net
  	if (br->multicast_disabled || !netif_running(br->dev))
  		goto out;
  
@@ -370,7 +465,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  
  out:
  	spin_unlock(&br->multicast_lock);
-@@ -890,7 +938,10 @@ void br_multicast_disable_port(struct ne
+@@ -890,7 +937,10 @@ void br_multicast_disable_port(struct ne
  	if (!hlist_unhashed(&port->rlist))
  		hlist_del_init_rcu(&port->rlist);
  	del_timer(&port->multicast_router_timer);
@@ -382,7 +477,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	spin_unlock(&br->multicast_lock);
  }
  
-@@ -1015,6 +1066,17 @@ static int br_ip6_multicast_mld2_report(
+@@ -1015,6 +1065,17 @@ static int br_ip6_multicast_mld2_report(
  }
  #endif
  
@@ -400,19 +495,22 @@  Date:   Tue May 21 21:52:54 2013 +0000
  /*
   * Add port to rotuer_list
   *  list is maintained ordered by pointer value
-@@ -1065,12 +1127,13 @@ timer:
+@@ -1065,12 +1126,14 @@ timer:
  
  static void br_multicast_query_received(struct net_bridge *br,
  					struct net_bridge_port *port,
 -					int saddr)
-+					struct bridge_mcast_querier *querier,
-+					int saddr,
-+					unsigned long max_delay)
- {
- 	if (saddr)
+-{
+-	if (saddr)
 -		mod_timer(&br->multicast_querier_timer,
 -			  jiffies + br->multicast_querier_interval);
 -	else if (timer_pending(&br->multicast_querier_timer))
++					struct bridge_mcast_querier *querier,
++					int saddr,
++					bool is_general_query,
++					unsigned long max_delay)
++{
++	if (saddr && is_general_query)
 +		br_multicast_update_querier_timer(br, querier, max_delay);
 +	else if (timer_pending(&querier->timer))
  		return;
@@ -427,17 +525,33 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	group = ih->group;
  
  	if (skb->len == sizeof(*ih)) {
-@@ -1122,6 +1183,9 @@ static int br_ip4_multicast_query(struct
+@@ -1122,6 +1183,17 @@ static int br_ip4_multicast_query(struct
  			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
  	}
  
++	/* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
++	 * all-systems destination addresses (224.0.0.1) for general queries
++	 */
++	if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
++		err = -EINVAL;
++		goto out;
++	}
++
 +	br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
-+				    max_delay);
++				    !group, max_delay);
 +
  	if (!group)
  		goto out;
  
-@@ -1174,8 +1238,6 @@ static int br_ip6_multicast_query(struct
+@@ -1166,6 +1238,7 @@ static int br_ip6_multicast_query(struct
+ 	unsigned long max_delay;
+ 	unsigned long now = jiffies;
+ 	const struct in6_addr *group = NULL;
++	bool is_general_query;
+ 	int err = 0;
+ 	u16 vid = 0;
+ 
+@@ -1174,8 +1247,6 @@ static int br_ip6_multicast_query(struct
  	    (port && port->state == BR_STATE_DISABLED))
  		goto out;
  
@@ -446,17 +560,28 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
  	if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
  		err = -EINVAL;
-@@ -1203,6 +1265,9 @@ static int br_ip6_multicast_query(struct
+@@ -1203,6 +1274,20 @@ static int br_ip6_multicast_query(struct
  		max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
  	}
  
++	is_general_query = group && ipv6_addr_any(group);
++
++	/* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
++	 * all-nodes destination address (ff02::1) for general queries
++	 */
++	if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
++		err = -EINVAL;
++		goto out;
++	}
++
 +	br_multicast_query_received(br, port, &br->ip6_querier,
-+				    !ipv6_addr_any(&ip6h->saddr), max_delay);
++				    !ipv6_addr_any(&ip6h->saddr),
++				    is_general_query, max_delay);
 +
  	if (!group)
  		goto out;
  
-@@ -1235,7 +1300,9 @@ out:
+@@ -1235,7 +1320,9 @@ out:
  
  static void br_multicast_leave_group(struct net_bridge *br,
  				     struct net_bridge_port *port,
@@ -467,7 +592,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  {
  	struct net_bridge_mdb_htable *mdb;
  	struct net_bridge_mdb_entry *mp;
-@@ -1246,7 +1313,7 @@ static void br_multicast_leave_group(str
+@@ -1246,7 +1333,7 @@ static void br_multicast_leave_group(str
  	spin_lock(&br->multicast_lock);
  	if (!netif_running(br->dev) ||
  	    (port && port->state == BR_STATE_DISABLED) ||
@@ -476,7 +601,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  		goto out;
  
  	mdb = mlock_dereference(br->mdb, br);
-@@ -1254,6 +1321,31 @@ static void br_multicast_leave_group(str
+@@ -1254,6 +1341,31 @@ static void br_multicast_leave_group(str
  	if (!mp)
  		goto out;
  
@@ -508,7 +633,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
  		struct net_bridge_port_group __rcu **pp;
  
-@@ -1306,7 +1398,6 @@ static void br_multicast_leave_group(str
+@@ -1306,7 +1418,6 @@ static void br_multicast_leave_group(str
  
  		break;
  	}
@@ -516,7 +641,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  out:
  	spin_unlock(&br->multicast_lock);
  }
-@@ -1317,6 +1408,8 @@ static void br_ip4_multicast_leave_group
+@@ -1317,6 +1428,8 @@ static void br_ip4_multicast_leave_group
  					 __u16 vid)
  {
  	struct br_ip br_group;
@@ -525,7 +650,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  
  	if (ipv4_is_local_multicast(group))
  		return;
-@@ -1325,7 +1418,7 @@ static void br_ip4_multicast_leave_group
+@@ -1325,7 +1438,7 @@ static void br_ip4_multicast_leave_group
  	br_group.proto = htons(ETH_P_IP);
  	br_group.vid = vid;
  
@@ -534,7 +659,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
-@@ -1335,15 +1428,18 @@ static void br_ip6_multicast_leave_group
+@@ -1335,15 +1448,18 @@ static void br_ip6_multicast_leave_group
  					 __u16 vid)
  {
  	struct br_ip br_group;
@@ -555,7 +680,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  }
  #endif
  
-@@ -1473,8 +1569,14 @@ static int br_multicast_ipv6_rcv(struct 
+@@ -1473,8 +1589,14 @@ static int br_multicast_ipv6_rcv(struct
  	 *  - MLD has always Router Alert hop-by-hop option
  	 *  - But we do not support jumbrograms.
  	 */
@@ -572,7 +697,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	    ip6h->payload_len == 0)
  		return 0;
  
-@@ -1605,19 +1707,32 @@ int br_multicast_rcv(struct net_bridge *
+@@ -1605,19 +1727,32 @@ int br_multicast_rcv(struct net_bridge *
  	return 0;
  }
  
@@ -612,7 +737,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  
  void br_multicast_init(struct net_bridge *br)
  {
-@@ -1626,6 +1741,7 @@ void br_multicast_init(struct net_bridge
+@@ -1626,6 +1761,7 @@ void br_multicast_init(struct net_bridge
  
  	br->multicast_router = 1;
  	br->multicast_querier = 0;
@@ -620,7 +745,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	br->multicast_last_member_count = 2;
  	br->multicast_startup_query_count = 2;
  
-@@ -1636,23 +1752,43 @@ void br_multicast_init(struct net_bridge
+@@ -1636,23 +1772,43 @@ void br_multicast_init(struct net_bridge
  	br->multicast_querier_interval = 255 * HZ;
  	br->multicast_membership_interval = 260 * HZ;
  
@@ -670,7 +795,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  }
  
  void br_multicast_stop(struct net_bridge *br)
-@@ -1664,8 +1800,12 @@ void br_multicast_stop(struct net_bridge
+@@ -1664,8 +1820,12 @@ void br_multicast_stop(struct net_bridge
  	int i;
  
  	del_timer_sync(&br->multicast_router_timer);
@@ -685,7 +810,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  
  	spin_lock_bh(&br->multicast_lock);
  	mdb = mlock_dereference(br->mdb, br);
-@@ -1767,18 +1907,24 @@ unlock:
+@@ -1767,18 +1927,24 @@ unlock:
  	return err;
  }
  
@@ -713,7 +838,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	}
  }
  
-@@ -1813,7 +1959,10 @@ rollback:
+@@ -1813,7 +1979,10 @@ rollback:
  			goto rollback;
  	}
  
@@ -725,7 +850,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  
  unlock:
  	spin_unlock_bh(&br->multicast_lock);
-@@ -1823,6 +1972,8 @@ unlock:
+@@ -1823,6 +1992,8 @@ unlock:
  
  int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
  {
@@ -734,7 +859,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  	val = !!val;
  
  	spin_lock_bh(&br->multicast_lock);
-@@ -1830,8 +1981,22 @@ int br_multicast_set_querier(struct net_
+@@ -1830,8 +2001,22 @@ int br_multicast_set_querier(struct net_
  		goto unlock;
  
  	br->multicast_querier = val;
@@ -918,7 +1043,7 @@  Date:   Tue May 21 21:52:54 2013 +0000
  static ssize_t show_multicast_querier(struct device *d,
  				      struct device_attribute *attr,
  				      char *buf)
-@@ -734,6 +759,7 @@ static struct attribute *bridge_attrs[] 
+@@ -734,6 +759,7 @@ static struct attribute *bridge_attrs[]
  	&dev_attr_multicast_router.attr,
  	&dev_attr_multicast_snooping.attr,
  	&dev_attr_multicast_querier.attr,
diff --git a/target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch b/target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch
index a9c5d68..7ad2e2c 100644
--- a/target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch
+++ b/target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch
@@ -67,13 +67,13 @@ 
  	default:
 --- a/net/bridge/br_multicast.c
 +++ b/net/bridge/br_multicast.c
-@@ -802,7 +802,7 @@ static void __br_multicast_send_query(st
+@@ -801,7 +801,7 @@ static void __br_multicast_send_query(st
+ 
  	if (port) {
- 		__skb_push(skb, sizeof(struct ethhdr));
  		skb->dev = port->dev;
 -		NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
 +		BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
- 			dev_queue_xmit);
+ 			br_dev_queue_push_xmit);
  	} else
  		netif_rx(skb);
 --- a/net/bridge/br_netfilter.c