]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bridge: br_nd_send: validate ND option lengths
authorYang Yang <n05ec@lzu.edu.cn>
Thu, 26 Mar 2026 03:44:40 +0000 (03:44 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Mar 2026 03:37:14 +0000 (20:37 -0700)
br_nd_send() walks ND options according to option-provided lengths.
A malformed option can make the parser advance beyond the computed
option span or use a too-short source LLADDR option payload.

Validate option lengths against the remaining NS option area before
advancing, and only read source LLADDR when the option is large enough
for an Ethernet address.

Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
Cc: stable@vger.kernel.org
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20260326034441.2037420-3-n05ec@lzu.edu.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/bridge/br_arp_nd_proxy.c

index af3d1e33f50b83c6d5782aa5eeb23e24f6df2286..6b5595868a39c07e48748ce612555f350d8686e1 100644 (file)
@@ -288,12 +288,14 @@ 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]) {
+               if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) {
                        kfree_skb(reply);
                        return;
                }
                if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
-                       daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+                       if ((ns->opt[i + 1] << 3) >=
+                           sizeof(struct nd_opt_hdr) + ETH_ALEN)
+                               daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
                        break;
                }
        }