BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Íñigo Huguet" <ihuguet@riseup.net>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH net v3 2/3] net/ipv6: don't route packets with unknown source address
Date: Thu, 29 Oct 2026 19:12:46 +0000	[thread overview]
Message-ID: <sashiko-outbox-189854@kernel.org> (raw)
In-Reply-To: <20261028191103.623156-3-ihuguet@riseup.net>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] net/ipv6: uninitialized fib_result in ip6_is_local_saddr()
- [Medium] sctp: missing flowi6_flags initialization in sctp_v6_get_dst()
--

commit a60f53e33acaf53f5beb0a9e9e20fd1e7c8f5aac
Author: Íñigo Huguet <ihuguet@riseup.net>

net/ipv6: don't route packets with unknown source address

This patch prevents routing outbound IPv6 packets when the source address
is not configured on the host (with a fallback to FIB local routes for
loopback subnets), unless FLOWI_FLAG_ANYSRC is set in flowi6_flags.

[ ... ]

> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 25fe0ba98b1a6..8715cf43f00ac 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -1134,6 +1134,33 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
>  	return dst;
>  }
>  
> +/* Check if the address belongs to the host */
> +static bool ip6_is_local_saddr(struct net *net, struct in6_addr *saddr)
> +{
> +	struct fib6_result fib_result;
> +	struct flowi6 fl6;
> +	bool result;
> +
> +	if (ipv6_chk_addr_namespace(net, saddr) ||
> +	    ipv6_chk_acast_addr_src(net, NULL, saddr))
> +		return true;
> +
> +	/* Fallback to FIB local routes so that loopback subnets work. */
> +	memset(&fl6, 0, sizeof(fl6));
> +	fl6.daddr = *saddr;
> +	result = false;
> +
> +	rcu_read_lock();
> +	if (fib6_lookup(net, 0, &fl6, &fib_result, 0) == 0 &&
> +	    fib_result.fib6_type == RTN_LOCAL &&
> +	    fib_result.nh->nh_common.nhc_dev) {
> +		result = true;
> +	}
> +	rcu_read_unlock();
> +
> +	return result;
> +}

[Severity: Critical]
Should fib_result be zero-initialized in ip6_is_local_saddr() before
calling fib6_lookup()?

In net/ipv6/ip6_output.c, ip6_is_local_saddr() declares fib_result on the
stack without initializing it, leaving fib_result.rt6 with uninitialized
stack data.

When custom IPv6 FIB rules are present (net->ipv6.fib6_has_custom_rules is
true), fib6_lookup() in net/ipv6/fib6_rules.c calls fib_rules_lookup() with
arg.lookup_ptr = fib6_table_lookup and arg.result = &fib_result:

net/ipv6/fib6_rules.c:fib6_lookup() {
	if (net->ipv6.fib6_has_custom_rules) {
		struct fib_lookup_arg arg = {
			.lookup_ptr = fib6_table_lookup,
			.lookup_data = &oif,
			.result = res,
			.flags = FIB_LOOKUP_NOREF,
		};
		...
		err = fib_rules_lookup(net->ipv6.fib6_rules_ops,
				       flowi6_to_flowi(fl6), flags, &arg);

During rule evaluation, fib_rules_lookup() in net/core/fib_rules.c invokes
fib6_rule_action() -> fib6_rule_action_alt() -> fib6_table_lookup() ->
rt6_select(). In net/ipv6/route.c, rt6_select() and __find_rr_leaf() only
populate res->f6i, res->nh, res->fib6_flags, and res->fib6_type, leaving
res->rt6 untouched.

When fib6_rule_action() returns 0, fib_rules_lookup() then calls
fib6_rule_suppress() in net/ipv6/fib6_rules.c:

net/ipv6/fib6_rules.c:fib6_rule_suppress() {
	struct fib6_result *res = arg->result;
	struct rt6_info *rt = res->rt6;
	struct net_device *dev = NULL;

	if (!rt)
		return false;

	if (rt->rt6i_idev)
		dev = rt->rt6i_idev->dev;

	if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
		goto suppress_route;

Because fib_result.rt6 is uninitialized, any non-zero stack value causes
fib6_rule_suppress() to dereference rt->rt6i_idev and rt->rt6i_dst.plen,
and potentially call ip6_rt_put_flags() on an arbitrary stack address.

> @@ -1191,6 +1218,17 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
>  	if (err)
>  		goto out_err_release;
>  
> +	/* From RFC 4862, "an invalid address MUST NOT be used as the source
> +	 * address of outbound packets". Exceptions to this must set the ANYSRC
> +	 * flag (i.e. transparent sockets).
> +	 */
> +	if (!ipv6_addr_any(&fl6->saddr) &&
> +	    !(fl6->flowi6_flags & FLOWI_FLAG_ANYSRC) &&
> +	    !ip6_is_local_saddr(net, &fl6->saddr)) {
> +		err = -ENETUNREACH;
> +		goto out_err_release;
> +	}
> +
>  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
>  	/*
>  	 * Here if the dst entry we've looked up

[Severity: Medium]
Does sctp_v6_get_dst() in net/sctp/ipv6.c also need to set
fl6->flowi6_flags = inet_sk_flowi_flags(sk) so that transparent IPv6 SCTP
sockets continue to work with this check?

IPv6 SCTP supports IPV6_TRANSPARENT and allows binding to non-local IPv6
addresses via sctp_inet6_bind_verify() -> sctp_v6_available():

net/sctp/ipv6.c:sctp_v6_available() {
	...
	res = ipv6_can_nonlocal_bind(net, &sp->inet) ||
	      ipv6_chk_addr(net, in6, dev, 0);

However, in net/sctp/ipv6.c, sctp_v6_get_dst() zero-initializes _fl and
calls ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p) without setting
fl6->flowi6_flags from inet_sk_flowi_flags(sk):

net/sctp/ipv6.c:sctp_v6_get_dst() {
	...
	memset(&_fl, 0, sizeof(_fl));
	...
	dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
	...
		fl6->saddr = laddr->a.v6.sin6_addr;
		fl6->fl6_sport = laddr->a.v6.sin6_port;
		final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
		bdst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);

Because FLOWI_FLAG_ANYSRC is not set in fl6->flowi6_flags, outbound route
lookups for an IPv6 SCTP socket with IPV6_TRANSPARENT bound to a non-local
address will now fail in ip6_dst_lookup_tail() with -ENETUNREACH.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261028191103.623156-1-ihuguet@riseup.net?part=2

  parent reply	other threads:[~2026-10-29 19:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28 19:10 [PATCH net v3 0/3] net/ipv6: don't route packets with unknown source address Íñigo Huguet
2026-10-28 19:10 ` [PATCH net v3 1/3] net/ipv6: add ipv6_chk_addr_namespace Íñigo Huguet
2026-10-28 19:10 ` [PATCH net v3 2/3] net/ipv6: don't route packets with unknown source address Íñigo Huguet
2026-10-29  0:02   ` Kuniyuki Iwashima
2026-10-29  6:28     ` Íñigo Huguet
2026-10-29 19:12   ` sashiko-bot [this message]
2026-10-28 19:10 ` [PATCH net v3 3/3] selftests: net: add tests for saddr, anycast and loopback subnets Íñigo Huguet
2026-10-29 19:12   ` sashiko-bot

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=sashiko-outbox-189854@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=ihuguet@riseup.net \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox