[PATCH net 2/3] bridge: br_nd_send: validate ND option lengths

Yang Yang posted 3 patches 1 week ago
[PATCH net 2/3] bridge: br_nd_send: validate ND option lengths
Posted by Yang Yang 1 week ago
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>
---
 net/bridge/br_arp_nd_proxy.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index af3d1e33f50b8..6b5595868a39c 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -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;
 		}
 	}
-- 
2.43.0
Re: [PATCH net 2/3] bridge: br_nd_send: validate ND option lengths
Posted by Nikolay Aleksandrov 6 days, 17 hours ago
On 26/03/2026 05:44, Yang Yang wrote:
> 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>
> ---
>   net/bridge/br_arp_nd_proxy.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
> index af3d1e33f50b8..6b5595868a39c 100644
> --- a/net/bridge/br_arp_nd_proxy.c
> +++ b/net/bridge/br_arp_nd_proxy.c
> @@ -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;
>   		}
>   	}

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Re: [PATCH net 2/3] bridge: br_nd_send: validate ND option lengths
Posted by Ido Schimmel 1 week ago
On Thu, Mar 26, 2026 at 03:44:40AM +0000, Yang Yang wrote:
> 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>

The AI review [1] is correct that the length check for the
ND_OPT_SOURCE_LL_ADDR option is not strictly necessary, but it makes it
clear that the access is valid and it's harmless.

The other comment is about another existing issue in the code, but it's
less severe and shouldn't delay this patch.

[1] https://sashiko.dev/#/patchset/20260326034441.2037420-1-n05ec%40lzu.edu.cn