diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
| -rw-r--r-- | net/bridge/br_multicast.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index f03e2e98cd44..f701a21acb34 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1451,7 +1451,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1451 | struct net_bridge_port *port, | 1451 | struct net_bridge_port *port, |
| 1452 | struct sk_buff *skb) | 1452 | struct sk_buff *skb) |
| 1453 | { | 1453 | { |
| 1454 | struct sk_buff *skb2 = skb; | 1454 | struct sk_buff *skb2; |
| 1455 | struct ipv6hdr *ip6h; | 1455 | struct ipv6hdr *ip6h; |
| 1456 | struct icmp6hdr *icmp6h; | 1456 | struct icmp6hdr *icmp6h; |
| 1457 | u8 nexthdr; | 1457 | u8 nexthdr; |
| @@ -1490,15 +1490,15 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1490 | if (!skb2) | 1490 | if (!skb2) |
| 1491 | return -ENOMEM; | 1491 | return -ENOMEM; |
| 1492 | 1492 | ||
| 1493 | err = -EINVAL; | ||
| 1494 | if (!pskb_may_pull(skb2, offset + sizeof(struct icmp6hdr))) | ||
| 1495 | goto out; | ||
| 1496 | |||
| 1493 | len -= offset - skb_network_offset(skb2); | 1497 | len -= offset - skb_network_offset(skb2); |
| 1494 | 1498 | ||
| 1495 | __skb_pull(skb2, offset); | 1499 | __skb_pull(skb2, offset); |
| 1496 | skb_reset_transport_header(skb2); | 1500 | skb_reset_transport_header(skb2); |
| 1497 | 1501 | ||
| 1498 | err = -EINVAL; | ||
| 1499 | if (!pskb_may_pull(skb2, sizeof(*icmp6h))) | ||
| 1500 | goto out; | ||
| 1501 | |||
| 1502 | icmp6h = icmp6_hdr(skb2); | 1502 | icmp6h = icmp6_hdr(skb2); |
| 1503 | 1503 | ||
| 1504 | switch (icmp6h->icmp6_type) { | 1504 | switch (icmp6h->icmp6_type) { |
| @@ -1537,7 +1537,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1537 | switch (icmp6h->icmp6_type) { | 1537 | switch (icmp6h->icmp6_type) { |
| 1538 | case ICMPV6_MGM_REPORT: | 1538 | case ICMPV6_MGM_REPORT: |
| 1539 | { | 1539 | { |
| 1540 | struct mld_msg *mld = (struct mld_msg *)icmp6h; | 1540 | struct mld_msg *mld; |
| 1541 | if (!pskb_may_pull(skb2, sizeof(*mld))) { | ||
| 1542 | err = -EINVAL; | ||
| 1543 | goto out; | ||
| 1544 | } | ||
| 1545 | mld = (struct mld_msg *)skb_transport_header(skb2); | ||
| 1541 | BR_INPUT_SKB_CB(skb2)->mrouters_only = 1; | 1546 | BR_INPUT_SKB_CB(skb2)->mrouters_only = 1; |
| 1542 | err = br_ip6_multicast_add_group(br, port, &mld->mld_mca); | 1547 | err = br_ip6_multicast_add_group(br, port, &mld->mld_mca); |
| 1543 | break; | 1548 | break; |
| @@ -1550,15 +1555,18 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1550 | break; | 1555 | break; |
| 1551 | case ICMPV6_MGM_REDUCTION: | 1556 | case ICMPV6_MGM_REDUCTION: |
| 1552 | { | 1557 | { |
| 1553 | struct mld_msg *mld = (struct mld_msg *)icmp6h; | 1558 | struct mld_msg *mld; |
| 1559 | if (!pskb_may_pull(skb2, sizeof(*mld))) { | ||
| 1560 | err = -EINVAL; | ||
| 1561 | goto out; | ||
| 1562 | } | ||
| 1563 | mld = (struct mld_msg *)skb_transport_header(skb2); | ||
| 1554 | br_ip6_multicast_leave_group(br, port, &mld->mld_mca); | 1564 | br_ip6_multicast_leave_group(br, port, &mld->mld_mca); |
| 1555 | } | 1565 | } |
| 1556 | } | 1566 | } |
| 1557 | 1567 | ||
| 1558 | out: | 1568 | out: |
| 1559 | __skb_push(skb2, offset); | 1569 | kfree_skb(skb2); |
| 1560 | if (skb2 != skb) | ||
| 1561 | kfree_skb(skb2); | ||
| 1562 | return err; | 1570 | return err; |
| 1563 | } | 1571 | } |
| 1564 | #endif | 1572 | #endif |
