From: Danielle Ratson <danieller@nvidia.com>
To: <netdev@vger.kernel.org>
Cc: <dsahern@kernel.org>, <idosch@nvidia.com>, <davem@davemloft.net>,
<edumazet@google.com>, <kuba@kernel.org>, <pabeni@redhat.com>,
<horms@kernel.org>, <razor@blackwall.org>, <ja@ssi.bg>,
<petrm@nvidia.com>, <fw@strlen.de>, <kuniyu@google.com>,
<bridge@lists.linux.dev>, <linux-kernel@vger.kernel.org>,
Danielle Ratson <danieller@nvidia.com>
Subject: [PATCH net-next v2 5/5] bridge: Use ndisc_parse_options() to parse ND options in br_nd_send()
Date: Mon, 3 Aug 2026 14:25:05 +0300 [thread overview]
Message-ID: <20260803112505.613873-6-danieller@nvidia.com> (raw)
In-Reply-To: <20260803112505.613873-1-danieller@nvidia.com>
Replace the manual ND option parsing loop in br_nd_send() with
ndisc_parse_options(), which provides proper validation and avoids the
class of bugs that were fixed by commit 53fc685243bd ("bridge: Avoid
infinite loop when suppressing NS messages with invalid options") and
commit 850837965af1 ("bridge: br_nd_send: validate ND option lengths").
Use ndisc_opt_addr_data() to extract the source link-layer address
from the parsed options, which correctly validates the option length
for the underlying device type.
Export ndisc_parse_options() so that it can be resolved from the bridge
when it is built as a module (CONFIG_BRIDGE=m); otherwise modpost fails
with an undefined symbol.
Reviewed-by: Petr Machata <petrm@nvidia.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
Notes:
v2:
* Use EXPORT_SYMBOL_GPL() instead of EXPORT_SYMBOL() to export
ndisc_parse_options().
net/bridge/br_arp_nd_proxy.c | 32 +++++++++++++++++---------------
net/ipv6/ndisc.c | 1 +
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index 6b6de0eff38c..b6e5a86b6a92 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -255,15 +255,16 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
{
struct net_device *dev = request->dev;
struct net_bridge_vlan_group *vg;
+ struct ndisc_options ndopts;
struct nd_msg *na, *ns;
struct sk_buff *reply;
struct ipv6hdr *pip6;
int na_olen = 8; /* opt hdr + ETH_ALEN for target */
int ns_olen;
- int i, len;
u8 *daddr;
bool dad;
u16 pvid;
+ int len;
if (!dev)
return;
@@ -284,20 +285,21 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
daddr = eth_hdr(request)->h_source;
ns = (struct nd_msg *)skb_transport_header(request);
- /* Do we need option processing ? */
- 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] || i + (ns->opt[i + 1] << 3) > ns_olen) {
- kfree_skb(reply);
- return;
- }
- if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
- if ((ns->opt[i + 1] << 3) >=
- sizeof(struct nd_opt_hdr) + ETH_ALEN)
- daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
- break;
- }
+ /* Derive the option length from the IPv6 payload length so that any
+ * trailing L2 padding in the skb is not parsed as ND options.
+ */
+ ns_olen = ntohs(ipv6_hdr(request)->payload_len) - sizeof(*ns);
+ if (!ndisc_parse_options(dev, ns->opt, ns_olen, &ndopts)) {
+ kfree_skb(reply);
+ return;
+ }
+
+ if (ndopts.nd_opts_src_lladdr) {
+ u8 *lladdr;
+
+ lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
+ if (lladdr)
+ daddr = lladdr;
}
dad = ipv6_addr_any(&ipv6_hdr(request)->saddr);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index fe36b3f51285..2ceb655c4229 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -283,6 +283,7 @@ struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
}
return ndopts;
}
+EXPORT_SYMBOL_GPL(ndisc_parse_options);
int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
{
--
2.54.0
next prev parent reply other threads:[~2026-08-03 11:26 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 11:25 [PATCH net-next v2 0/5] bridge: Validate and clean up IPv6 neighbour suppression Danielle Ratson
2026-08-03 11:25 ` [PATCH net-next v2 1/5] bridge: Use direct pointer in br_is_nd_neigh_msg() Danielle Ratson
2026-08-05 8:06 ` Danielle Ratson
2026-08-03 11:25 ` [PATCH net-next v2 2/5] ipv6: ndisc: Add ndisc_check_ns_na() validation helper Danielle Ratson
2026-08-05 8:06 ` Danielle Ratson
2026-08-03 11:25 ` [PATCH net-next v2 3/5] bridge: Validate NS/NA messages using ndisc_check_ns_na() Danielle Ratson
2026-08-03 11:25 ` [PATCH net-next v2 4/5] bridge: Linearize skb once the ND message type is validated Danielle Ratson
2026-08-03 15:25 ` Nikolay Aleksandrov
2026-08-03 11:25 ` Danielle Ratson [this message]
2026-08-05 8:07 ` [PATCH net-next v2 5/5] bridge: Use ndisc_parse_options() to parse ND options in br_nd_send() Danielle Ratson
2026-08-07 23:40 ` [PATCH net-next v2 0/5] bridge: Validate and clean up IPv6 neighbour suppression patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260803112505.613873-6-danieller@nvidia.com \
--to=danieller@nvidia.com \
--cc=bridge@lists.linux.dev \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=ja@ssi.bg \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=petrm@nvidia.com \
--cc=razor@blackwall.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.