aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2015-01-19 01:13:25 +0000
committerFelix Fietkau <nbd@openwrt.org>2015-01-19 01:13:25 +0000
commit0030bded51106a9e6ad4e2c41d90d00d04ce26b2 (patch)
tree883ba54cd3da83665f21315834caaec643c1f887
parentae69e6dbf8dbd95128838f2b55b4057bc29ada02 (diff)
downloadupstream-0030bded51106a9e6ad4e2c41d90d00d04ce26b2.tar.gz
upstream-0030bded51106a9e6ad4e2c41d90d00d04ce26b2.tar.bz2
upstream-0030bded51106a9e6ad4e2c41d90d00d04ce26b2.zip
kernel: bridge: multicast: backport a few more fixes for 3.10
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> Backport of r43841 git-svn-id: svn://svn.openwrt.org/openwrt/branches/barrier_breaker@44049 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--target/linux/generic/patches-3.10/070-net_bridge_backports.patch193
-rw-r--r--target/linux/generic/patches-3.10/644-bridge_optimize_netfilter_hooks.patch6
2 files changed, 162 insertions, 37 deletions
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 f303c3a094..48d6eda024 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 a9c5d689fe..7ad2e2c47f 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