summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorYang Yang <n05ec@lzu.edu.cn>2026-03-26 06:44:40 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-04-11 15:19:31 +0300
commite0bfd6d4dc77ab345b6c65eef0cfe9b2f69085aa (patch)
treeca815ff47ccbdaab86a0bcd3ead505428f43509f /net
parent2e5cbab8ccbfc7d4a3d8a21d3c2a1f2c1aa29b5b (diff)
downloadlinux-e0bfd6d4dc77ab345b6c65eef0cfe9b2f69085aa.tar.xz
bridge: br_nd_send: validate ND option lengths
commit 850837965af15707fd3142c1cf3c5bfaf022299b upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_arp_nd_proxy.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index b8bfc336ff7a..f033a5167560 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -285,12 +285,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;
}
}