Re: [PATCH net 1/3] bridge: br_nd_send: linearize skb before parsing ND options
Nikolay Aleksandrov <[email protected]>
| Newsgroups | gmane.linux.network.bridge,gmane.linux.network,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
On 26/03/2026 05:44, Yang Yang wrote:
> br_nd_send() parses neighbour discovery options from ns->opt[] and
> assumes that these options are in the linear part of request.
>
> Its callers only guarantee that the ICMPv6 header and target address
> are available, so the option area can still be non-linear. Parsing
> ns->opt[] in that case can access data past the linear buffer.
>
> Linearize request before option parsing and derive ns from the linear
> network header.
>
> Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
> Reported-by: Yifan Wu <[email protected]>
> Reported-by: Juefei Pu <[email protected]>
> Tested-by: Ao Zhou <[email protected]>
> Co-developed-by: Yuan Tan <[email protected]>
> Signed-off-by: Yuan Tan <[email protected]>
> Suggested-by: Xin Liu <[email protected]>
> Signed-off-by: Yang Yang <[email protected]>
> ---
> net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
> index 1e2b51769eec8..af3d1e33f50b8 100644
> --- a/net/bridge/br_arp_nd_proxy.c
> +++ b/net/bridge/br_arp_nd_proxy.c
> @@ -251,12 +251,12 @@ struct nd_msg *br_is_nd_neigh_msg(const struct sk_buff *skb, struct nd_msg *msg)
>
> static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
> struct sk_buff *request, struct neighbour *n,
> - __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
> + __be16 vlan_proto, u16 vlan_tci)
> {
> struct net_device *dev = request->dev;
> struct net_bridge_vlan_group *vg;
> + struct nd_msg *na, *ns;
> struct sk_buff *reply;
> - struct nd_msg *na;
> struct ipv6hdr *pip6;
> int na_olen = 8; /* opt hdr + ETH_ALEN for target */
> int ns_olen;
> @@ -264,7 +264,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
> u8 *daddr;
> u16 pvid;
>
> - if (!dev)
> + if (!dev || skb_linearize(request))
> return;
>
> len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
> @@ -281,6 +281,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
> skb_set_mac_header(reply, 0);
>
> daddr = eth_hdr(request)->h_source;
> + ns = (struct nd_msg *)(skb_network_header(request) +
> + sizeof(struct ipv6hdr));
>
> /* Do we need option processing ? */
> ns_olen = request->len - (skb_network_offset(request) +
> @@ -472,9 +474,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
> if (vid != 0)
> br_nd_send(br, p, skb, n,
> skb->vlan_proto,
> - skb_vlan_tag_get(skb), msg);
> + skb_vlan_tag_get(skb));
> else
> - br_nd_send(br, p, skb, n, 0, 0, msg);
> + br_nd_send(br, p, skb, n, 0, 0);
> replied = true;
> }
>
Acked-by: Nikolay Aleksandrov <[email protected]>