Commit 58957012 authored by Linus Lüssing's avatar Linus Lüssing Committed by Greg Kroah-Hartman

bridge: fix igmp / mld query parsing

[ Upstream commit 856ce5d0 ]

With the newly introduced helper functions the skb pulling is hidden
in the checksumming function - and undone before returning to the
caller.

The IGMP and MLD query parsing functions in the bridge still
assumed that the skb is pointing to the beginning of the IGMP/MLD
message while it is now kept at the beginning of the IPv4/6 header.

If there is a querier somewhere else, then this either causes
the multicast snooping to stay disabled even though it could be
enabled. Or, if we have the querier enabled too, then this can
create unnecessary IGMP / MLD query messages on the link.

Fixing this by taking the offset between IP and IGMP/MLD header into
account, too.

Fixes: 9afd85c9 ("net: Export IGMP/MLD message validation code")
Reported-by: default avatarSimon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: default avatarLinus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 97c2160d
...@@ -1270,6 +1270,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, ...@@ -1270,6 +1270,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
struct br_ip saddr; struct br_ip saddr;
unsigned long max_delay; unsigned long max_delay;
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned int offset = skb_transport_offset(skb);
__be32 group; __be32 group;
int err = 0; int err = 0;
...@@ -1280,14 +1281,14 @@ static int br_ip4_multicast_query(struct net_bridge *br, ...@@ -1280,14 +1281,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
group = ih->group; group = ih->group;
if (skb->len == sizeof(*ih)) { if (skb->len == offset + sizeof(*ih)) {
max_delay = ih->code * (HZ / IGMP_TIMER_SCALE); max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
if (!max_delay) { if (!max_delay) {
max_delay = 10 * HZ; max_delay = 10 * HZ;
group = 0; group = 0;
} }
} else if (skb->len >= sizeof(*ih3)) { } else if (skb->len >= offset + sizeof(*ih3)) {
ih3 = igmpv3_query_hdr(skb); ih3 = igmpv3_query_hdr(skb);
if (ih3->nsrcs) if (ih3->nsrcs)
goto out; goto out;
...@@ -1348,6 +1349,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -1348,6 +1349,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
struct br_ip saddr; struct br_ip saddr;
unsigned long max_delay; unsigned long max_delay;
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned int offset = skb_transport_offset(skb);
const struct in6_addr *group = NULL; const struct in6_addr *group = NULL;
bool is_general_query; bool is_general_query;
int err = 0; int err = 0;
...@@ -1357,8 +1359,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -1357,8 +1359,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED)) (port && port->state == BR_STATE_DISABLED))
goto out; goto out;
if (skb->len == sizeof(*mld)) { if (skb->len == offset + sizeof(*mld)) {
if (!pskb_may_pull(skb, sizeof(*mld))) { if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -1367,7 +1369,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -1367,7 +1369,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (max_delay) if (max_delay)
group = &mld->mld_mca; group = &mld->mld_mca;
} else { } else {
if (!pskb_may_pull(skb, sizeof(*mld2q))) { if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment