| From d3047feaf89dd26c3ca49b866a48b094bdb90c66 Mon Sep 17 00:00:00 2001 |
| From: Ido Schimmel <idosch@mellanox.com> |
| Date: Mon, 1 Jun 2020 15:58:54 +0300 |
| Subject: [PATCH] bridge: Avoid infinite loop when suppressing NS messages with |
| invalid options |
| |
| commit 53fc685243bd6fb90d90305cea54598b78d3cbfc upstream. |
| |
| When neighbor suppression is enabled the bridge device might reply to |
| Neighbor Solicitation (NS) messages on behalf of remote hosts. |
| |
| In case the NS message includes the "Source link-layer address" option |
| [1], the bridge device will use the specified address as the link-layer |
| destination address in its reply. |
| |
| To avoid an infinite loop, break out of the options parsing loop when |
| encountering an option with length zero and disregard the NS message. |
| |
| This is consistent with the IPv6 ndisc code and RFC 4886 which states |
| that "Nodes MUST silently discard an ND packet that contains an option |
| with length zero" [2]. |
| |
| [1] https://tools.ietf.org/html/rfc4861#section-4.3 |
| [2] https://tools.ietf.org/html/rfc4861#section-4.6 |
| |
| Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports") |
| Signed-off-by: Ido Schimmel <idosch@mellanox.com> |
| Reported-by: Alla Segal <allas@mellanox.com> |
| Tested-by: Alla Segal <allas@mellanox.com> |
| Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c |
| index 37908561a64b..b18cdf03edb3 100644 |
| --- a/net/bridge/br_arp_nd_proxy.c |
| +++ b/net/bridge/br_arp_nd_proxy.c |
| @@ -276,6 +276,10 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p, |
| ns_olen = request->len - (skb_network_offset(request) + |
| sizeof(struct ipv6hdr)) - sizeof(*ns); |
| for (i = 0; i < ns_olen - 1; i += (ns->opt[i + 1] << 3)) { |
| + if (!ns->opt[i + 1]) { |
| + kfree_skb(reply); |
| + return; |
| + } |
| if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) { |
| daddr = ns->opt + i + sizeof(struct nd_opt_hdr); |
| break; |
| -- |
| 2.27.0 |
| |