* [PATCH net] net/ipv6: don't route packets with unknown source address
@ 2026-09-01 11:50 Íñigo Huguet
2026-09-01 17:32 ` Matthieu Baerts
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Íñigo Huguet @ 2026-09-01 11:50 UTC (permalink / raw)
To: David Ahern, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Neal Cardwell, Ido Schimmel,
Pablo Neira Ayuso, Florian Westphal, Willem de Bruijn
Cc: Íñigo Huguet, Simon Horman, Kuniyuki Iwashima,
Phil Sutter, Daniel Borkmann, Fernando Fernandez Mancera,
Alexei Starovoitov, Junseo Lim, Leon Hwang, Xuanqiang Luo,
Willem de Bruijn, Kees Cook, Qi Tang, Jeff Layton, Joe Damato,
Breno Leitao, Li RongQing, open list:VRF, open list,
open list:NETFILTER, open list:NETFILTER,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
Don't allow routing packets with a source address that is not configured
in the host. Allow it only in certain cases like when using a
transparent socket, by setting the ANYSRC flag in flowi_flags.
Until now, it was possible to send such a packet if a route can be found
in the routing table for it. For example:
1. Configure an address 1:2::3:4/64 and a static route 1:2::/64
2. Establish a TCP connection to 1:2::3:4
3. Remove the address from the interface, but keep the route.
4. Packets are still sent out by the TCP connection because of
the static route. No incoming packets are accepted, though.
This patch prevents the outgoing packets to be sent in normal
circumnstances.
This aligns the behaviour with the IPv4 stack. To determine the places
where the ANYSRC needs to be set, I set the flag in the same places as
the IPv4 stack does.
Apart from consolidating the behaviour of both stacks, there is a more
important reason why this is needed. RFC 4862 states that "an invalid
address MUST NOT be used as the source address of outbound packets".
Therefore, sending packets with a source address considered "invalid",
like an expired address, is disallowed.
Signed-off-by: Íñigo Huguet <ihuguet@riseup.net>
---
Testing: tested with a manual reproducer executing the steps described
above. Tested also with transparent sockets to ensure that the packets
are sent in that case. Also executed the following selftests to prevent
potential regressions: fcnal-ipv6, fib_tests, fib-onlink-tests,
nft_nat, nft_tproxy_tcp, nft_tproxy_udp.
The change in the netfilter's ip6_route_me_harder function is the one
that I'm more unsure about. It was not clear to me the reason why it was
done like this in the IPv4 counterpart. Please review carefully.
---
drivers/net/vrf.c | 1 +
net/core/lwt_bpf.c | 1 +
net/ipv6/af_inet6.c | 1 +
net/ipv6/datagram.c | 1 +
net/ipv6/inet6_connection_sock.c | 2 ++
net/ipv6/ip6_output.c | 28 ++++++++++++++++++++++++++++
net/ipv6/netfilter.c | 10 ++++++++--
net/ipv6/ping.c | 1 +
net/ipv6/raw.c | 1 +
net/ipv6/syncookies.c | 1 +
net/ipv6/tcp_ipv6.c | 2 ++
net/ipv6/udp.c | 1 +
net/l2tp/l2tp_ip6.c | 2 ++
13 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index a0557a3a7026..6c09d5f46d6b 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -432,6 +432,7 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
fl6.flowlabel = ip6_flowinfo(iph);
fl6.flowi6_mark = skb->mark;
fl6.flowi6_proto = iph->nexthdr;
+ fl6.flowi6_flags = FLOWI_FLAG_ANYSRC;
dst = ip6_dst_lookup_flow(net, NULL, &fl6, NULL);
if (IS_ERR(dst) || dst == dst_null)
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
index da49364ec63d..e8b954282689 100644
--- a/net/core/lwt_bpf.c
+++ b/net/core/lwt_bpf.c
@@ -233,6 +233,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb)
fl6.flowi6_mark = skb->mark;
fl6.flowi6_uid = sock_net_uid(net, sk);
fl6.flowlabel = ip6_flowinfo(iph6);
+ fl6.flowi6_flags = FLOWI_FLAG_ANYSRC;
fl6.flowi6_proto = iph6->nexthdr;
fl6.daddr = iph6->daddr;
fl6.saddr = iph6->saddr;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 282912a11999..e55a36372ab2 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -820,6 +820,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl6->fl6_dport = inet->inet_dport;
fl6->fl6_sport = inet->inet_sport;
fl6->flowi6_uid = sk_uid(sk);
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6));
ip6_ecmp_set_mp_hash(sock_net(sk), fl6, sk->sk_txhash);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 38d7b4845281..0773bfa0342d 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -52,6 +52,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6,
fl6->flowi6_mark = sk->sk_mark;
fl6->fl6_dport = inet->inet_dport;
fl6->fl6_sport = inet->inet_sport;
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
fl6->flowlabel = ip6_make_flowinfo(np->tclass, np->flow_label);
fl6->flowi6_uid = sk_uid(sk);
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 3e4ce8cb478e..f295f3efe243 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -45,6 +45,7 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
fl6->flowi6_mark = ireq->ir_mark;
fl6->fl6_dport = ireq->ir_rmt_port;
fl6->fl6_sport = htons(ireq->ir_num);
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
fl6->flowi6_uid = sk_uid(sk);
security_req_classify_flow(req, flowi6_to_flowi_common(fl6));
@@ -71,6 +72,7 @@ struct dst_entry *inet6_csk_route_socket(struct sock *sk,
fl6->daddr = sk->sk_v6_daddr;
fl6->saddr = np->saddr;
fl6->flowlabel = np->flow_label;
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
IP6_ECN_flow_xmit(sk, fl6->flowlabel);
if (sk->sk_protocol == IPPROTO_TCP)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 8fc4766c8da9..57eebe347902 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1191,6 +1191,34 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
if (err)
goto out_err_release;
+ /* Routing packets with a source address not present in the host is
+ * disallowed unless the ANYSRC flag is set (i.e. with transparent sockets).
+ * The source address must be in the same L3 domain as the destination device.
+ */
+ if (!ipv6_addr_any(&fl6->saddr) &&
+ !(fl6->flowi6_flags & FLOWI_FLAG_ANYSRC)) {
+ struct net_device *oif_dev;
+
+ rcu_read_lock();
+ /* For local routes, (*dst)->dev can be 'lo', which has no l3mdev
+ * master, so that the L3 domain wouldn't match if the source
+ * address is in a VRF-enslaved device. To avoid that, check the
+ * outgoing interface from the flowi6 structure instead.
+ */
+ if (fl6->flowi6_oif)
+ oif_dev = dev_get_by_index_rcu(net, fl6->flowi6_oif);
+ else
+ oif_dev = (*dst)->dev;
+
+ if (!ipv6_chk_addr_and_flags(net, &fl6->saddr, oif_dev,
+ 1, 1, IFA_F_TENTATIVE))
+ err = -ENETUNREACH;
+ rcu_read_unlock();
+
+ if (err)
+ goto out_err_release;
+ }
+
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
/*
* Here if the dst entry we've looked up
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index a7025ec87035..7c19ecbec112 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -26,11 +26,11 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct sock *sk = sk_to_full_sk(sk_partial);
struct net_device *dev = skb_dst_dev(skb);
+ int daddr_type = ipv6_addr_type(&iph->daddr);
struct flow_keys flkeys;
unsigned int hh_len;
struct dst_entry *dst;
- int strict = (ipv6_addr_type(&iph->daddr) &
- (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
+ int strict = daddr_type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
struct flowi6 fl6 = {
.flowi6_l3mdev = l3mdev_master_ifindex(dev),
.flowi6_mark = skb->mark,
@@ -41,6 +41,12 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
};
int err;
+ fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0;
+ if (daddr_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL))
+ fl6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+ else
+ fl6.saddr = in6addr_any;
+
if (sk && sk->sk_bound_dev_if)
fl6.flowi6_oif = sk->sk_bound_dev_if;
else if (strict)
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 6e90d0bf9f3d..d0964396c2c5 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -140,6 +140,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
fl6.flowi6_proto = IPPROTO_ICMPV6;
fl6.saddr = np->saddr;
fl6.daddr = *daddr;
+ fl6.flowi6_flags = inet_sk_flowi_flags(sk);
fl6.flowi6_mark = ipc6.sockc.mark;
fl6.flowi6_uid = sk_uid(sk);
fl6.fl6_icmp_type = user_icmph.icmp6_type;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index b965258cf9e5..ef5ddbe7ac10 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -887,6 +887,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
+ fl6.flowi6_flags = inet_sk_flowi_flags(sk);
if (hdrincl)
fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index b581cb1ee2e8..3d665e93fcac 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -242,6 +242,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
fl6.flowi6_mark = ireq->ir_mark;
fl6.fl6_dport = ireq->ir_rmt_port;
fl6.fl6_sport = inet_sk(sk)->inet_sport;
+ fl6.flowi6_flags = inet_sk_flowi_flags(sk);
fl6.flowi6_uid = sk_uid(sk);
security_req_classify_flow(req, flowi6_to_flowi_common(&fl6));
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index df9c29eb5c1f..401a1297e7db 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -268,6 +268,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
fl6->flowi6_mark = sk->sk_mark;
fl6->fl6_dport = usin->sin6_port;
fl6->fl6_sport = inet->inet_sport;
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
if (IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) && !fl6->fl6_sport)
fl6->flowi6_flags = FLOWI_FLAG_ANY_SPORT;
fl6->flowi6_uid = sk_uid(sk);
@@ -979,6 +980,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
fl6.fl6_dport = t1->dest;
fl6.fl6_sport = t1->source;
fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
+ fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0;
security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
/* Pass a socket to ip6_dst_lookup either it is for RST
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 93478d1ad576..5154d445ba9c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1656,6 +1656,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (ipv6_addr_any(&fl6->saddr) && !ipv6_addr_any(&np->saddr))
fl6->saddr = np->saddr;
fl6->fl6_sport = inet->inet_sport;
+ fl6->flowi6_flags = inet_sk_flowi_flags(sk);
if (cgroup_bpf_enabled(CGROUP_UDP6_SENDMSG) && !connected) {
err = BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk,
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index bdaae1b64d25..22ae5bc2669a 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -633,6 +633,8 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
else if (!fl6.flowi6_oif)
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
+ fl6.flowi6_flags = inet_sk_flowi_flags(sk);
+
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net] net/ipv6: don't route packets with unknown source address
2026-09-01 11:50 [PATCH net] net/ipv6: don't route packets with unknown source address Íñigo Huguet
@ 2026-09-01 17:32 ` Matthieu Baerts
2026-09-02 10:08 ` Íñigo Huguet
2026-09-02 6:43 ` [syzbot ci] " syzbot ci
2026-09-02 11:51 ` [PATCH net] " sashiko-bot
2 siblings, 1 reply; 5+ messages in thread
From: Matthieu Baerts @ 2026-09-01 17:32 UTC (permalink / raw)
To: Íñigo Huguet, David Ahern, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell,
Ido Schimmel, Pablo Neira Ayuso, Florian Westphal,
Willem de Bruijn
Cc: Simon Horman, Kuniyuki Iwashima, Phil Sutter, Daniel Borkmann,
Fernando Fernandez Mancera, Alexei Starovoitov, Junseo Lim,
Leon Hwang, Xuanqiang Luo, Willem de Bruijn, Kees Cook, Qi Tang,
Jeff Layton, Joe Damato, Breno Leitao, Li RongQing, open list:VRF,
open list, open list:NETFILTER, open list:NETFILTER,
open list:BPF [MISC] :Keyword:(?:b|_)bpf(?:b|_)
Hi Íñigo,
On 01/09/2026 13:50, Íñigo Huguet wrote:
> Don't allow routing packets with a source address that is not configured
> in the host. Allow it only in certain cases like when using a
> transparent socket, by setting the ANYSRC flag in flowi_flags.
>
> Until now, it was possible to send such a packet if a route can be found
> in the routing table for it. For example:
> 1. Configure an address 1:2::3:4/64 and a static route 1:2::/64
> 2. Establish a TCP connection to 1:2::3:4
> 3. Remove the address from the interface, but keep the route.
> 4. Packets are still sent out by the TCP connection because of
> the static route. No incoming packets are accepted, though.
>
> This patch prevents the outgoing packets to be sent in normal
> circumnstances.
>
> This aligns the behaviour with the IPv4 stack. To determine the places
> where the ANYSRC needs to be set, I set the flag in the same places as
> the IPv4 stack does.
>
> Apart from consolidating the behaviour of both stacks, there is a more
> important reason why this is needed. RFC 4862 states that "an invalid
> address MUST NOT be used as the source address of outbound packets".
> Therefore, sending packets with a source address considered "invalid",
> like an expired address, is disallowed.
Thank you for looking at this, but I think your patch is causing
multiple KASAN warnings, e.g.
https://netdev-ctrl.bots.linux.dev/logs/vmksft/net-extra-dbg/results/804584/24-connect-deny-ipv6/stderr
And a few more, see:
https://netdev.bots.linux.dev/branch_deltas/net-next-2026-09-01--15-01.html
Cheers,
Matt
--
pw-bot: cr
^ permalink raw reply [flat|nested] 5+ messages in thread
* [syzbot ci] Re: net/ipv6: don't route packets with unknown source address
2026-09-01 11:50 [PATCH net] net/ipv6: don't route packets with unknown source address Íñigo Huguet
2026-09-01 17:32 ` Matthieu Baerts
@ 2026-09-02 6:43 ` syzbot ci
2026-09-02 11:51 ` [PATCH net] " sashiko-bot
2 siblings, 0 replies; 5+ messages in thread
From: syzbot ci @ 2026-09-02 6:43 UTC (permalink / raw)
To: andrew, ast, bpf, coreteam, daniel, davem, dsahern, edumazet,
fmancera, fw, horms, idosch, ihuguet, jlayton, joe, kees, kuba,
kuniyu, leitao, leon.hwang, linux-kernel, lirongqing,
luoxuanqiang, ncardwell, netdev, netfilter-devel, pabeni, pablo,
phil, tpluszz77, willemb, willemdebruijn.kernel, zirajs7
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] net/ipv6: don't route packets with unknown source address
https://lore.kernel.org/all/20260901115021.50057-1-ihuguet@riseup.net
* [PATCH net] net/ipv6: don't route packets with unknown source address
and found the following issues:
* KASAN: slab-out-of-bounds Read in tcp_v6_send_response
* KASAN: use-after-free Read in tcp_v6_send_response
Full report is available here:
https://ci.syzbot.org/series/bf5b7c3c-6165-4e2e-b403-34a698f5ee76
***
KASAN: slab-out-of-bounds Read in tcp_v6_send_response
tree: net
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git
base: 1d2929d0850fff683b8aff051275945e65f082c8
arch: amd64
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
config: https://ci.syzbot.org/builds/19ac2ebf-5913-40a0-982b-446415180382/config
syz repro: https://ci.syzbot.org/findings/103185a7-eed2-413d-9bb8-0cfd4d802dbb/syz_repro
==================================================================
BUG: KASAN: slab-out-of-bounds in instrument_atomic_read include/linux/instrumented.h:82 [inline]
BUG: KASAN: slab-out-of-bounds in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline]
BUG: KASAN: slab-out-of-bounds in inet_sk_flowi_flags include/net/inet_sock.h:411 [inline]
BUG: KASAN: slab-out-of-bounds in tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983
Read of size 8 at addr ffff8881bc3cecb8 by task kworker/u8:3/5678
CPU: 1 UID: 0 PID: 5678 Comm: kworker/u8:3 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Workqueue: krdsd rds_tcp_accept_worker
Call Trace:
<IRQ>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
check_region_inline mm/kasan/generic.c:-1 [inline]
kasan_check_range+0x264/0x2c0 mm/kasan/generic.c:200
instrument_atomic_read include/linux/instrumented.h:82 [inline]
_test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline]
inet_sk_flowi_flags include/net/inet_sock.h:411 [inline]
tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983
tcp_v6_send_ack net/ipv6/tcp_ipv6.c:1149 [inline]
tcp_v6_timewait_ack+0x2c6/0x4c0 net/ipv6/tcp_ipv6.c:1201
tcp_v6_rcv+0x1f09/0x2d90 net/ipv6/tcp_ipv6.c:1993
ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479
ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
__netif_receive_skb_one_core net/core/dev.c:6264 [inline]
__netif_receive_skb net/core/dev.c:6377 [inline]
process_backlog+0x795/0x18b0 net/core/dev.c:6728
__napi_poll+0xaa/0x330 net/core/dev.c:7787
napi_poll net/core/dev.c:7850 [inline]
net_rx_action+0x61d/0xf50 net/core/dev.c:8007
handle_softirqs+0x226/0x860 kernel/softirq.c:645
do_softirq+0x77/0xd0 kernel/softirq.c:546
</IRQ>
<TASK>
__local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
local_bh_enable include/linux/bottom_half.h:33 [inline]
rcu_read_unlock_bh include/linux/rcupdate.h:923 [inline]
__dev_queue_xmit+0x1edc/0x3820 net/core/dev.c:4961
NF_HOOK_COND include/linux/netfilter.h:314 [inline]
ip6_output+0x337/0x540 net/ipv6/ip6_output.c:248
dst_output include/net/dst.h:471 [inline]
NF_HOOK include/linux/netfilter.h:325 [inline]
ip6_xmit+0x117f/0x1a60 net/ipv6/ip6_output.c:381
inet6_csk_xmit+0x397/0x660 net/ipv6/inet6_connection_sock.c:123
__tcp_transmit_skb+0x2640/0x47c0 net/ipv4/tcp_output.c:1717
tcp_transmit_skb net/ipv4/tcp_output.c:1734 [inline]
tcp_write_xmit+0x1bfa/0x6400 net/ipv4/tcp_output.c:3062
__tcp_push_pending_frames+0x96/0x380 net/ipv4/tcp_output.c:3245
__tcp_close+0x56e/0xe70 net/ipv4/tcp.c:3220
tcp_close+0x28/0x110 net/ipv4/tcp.c:3311
inet_release+0x143/0x190 net/ipv4/af_inet.c:442
__sock_release net/socket.c:735 [inline]
sock_release+0x85/0x150 net/socket.c:763
rds_tcp_accept_one+0x62c/0xd40 net/rds/tcp_listen.c:341
rds_tcp_accept_worker+0x1d/0x70 net/rds/tcp.c:556
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
kthread+0x38b/0x480 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
The buggy address belongs to the object at ffff8881bc3ceb80
which belongs to the cache tw_sock_TCPv6 of size 304
The buggy address is located 8 bytes to the right of
allocated 304-byte region [ffff8881bc3ceb80, ffff8881bc3cecb0)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff8881bc3ce8a0 pfn:0x1bc3ce
head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
memcg:ffff8881bb1a4301
flags: 0x57ff00000000240(workingset|head|node=1|zone=2|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 057ff00000000240 ffff8881042e0640 ffff88816fedf1c8 ffff88816fedf1c8
raw: ffff8881bc3ce8a0 0000000200160006 00000000f5000000 ffff8881bb1a4301
head: 057ff00000000240 ffff8881042e0640 ffff88816fedf1c8 ffff88816fedf1c8
head: ffff8881bc3ce8a0 0000000200160006 00000000f5000000 ffff8881bb1a4301
head: 057ff00000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5678, tgid 5678 (kworker/u8:3), ts 57920184007
set_page_owner include/linux/page_owner.h:33 [inline]
post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1871
prep_new_page mm/page_alloc.c:1879 [inline]
get_page_from_freelist+0x2209/0x2280 mm/page_alloc.c:3943
__alloc_frozen_pages_noprof+0x217/0x5a0 mm/page_alloc.c:5436
alloc_slab_page mm/slub.c:3347 [inline]
allocate_slab+0x7d/0x620 mm/slub.c:3462
new_slab mm/slub.c:3513 [inline]
refill_objects+0x2d5/0x350 mm/slub.c:7410
refill_sheaf mm/slub.c:2885 [inline]
__pcs_replace_empty_main+0x2c8/0x6c0 mm/slub.c:4774
alloc_from_pcs mm/slub.c:4850 [inline]
slab_alloc_node mm/slub.c:4984 [inline]
kmem_cache_alloc_noprof+0x399/0x600 mm/slub.c:5010
inet_twsk_alloc+0xe3/0x8d0 net/ipv4/inet_timewait_sock.c:178
tcp_time_wait+0x5d/0xee0 net/ipv4/tcp_minisocks.c:333
tcp_rcv_state_process+0xba1/0x4980 net/ipv4/tcp_input.c:-1
tcp_v6_do_rcv+0xf3d/0x1c70 net/ipv6/tcp_ipv6.c:1653
tcp_v6_rcv+0x2496/0x2d90 net/ipv6/tcp_ipv6.c:1906
ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479
ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545
page last free pid 24 tgid 24 ts 57909757259 stack trace:
reset_page_owner include/linux/page_owner.h:26 [inline]
__free_pages_prepare mm/page_alloc.c:1418 [inline]
__free_frozen_pages+0xc93/0xd90 mm/page_alloc.c:2962
rcu_do_batch kernel/rcu/tree.c:2650 [inline]
rcu_core+0x926/0x1260 kernel/rcu/tree.c:2919
handle_softirqs+0x226/0x860 kernel/softirq.c:645
__do_softirq kernel/softirq.c:679 [inline]
invoke_softirq kernel/softirq.c:519 [inline]
__irq_exit_rcu+0xcb/0x220 kernel/softirq.c:767
irq_exit_rcu+0x9/0x30 kernel/softirq.c:784
instr_sysvec_call_function_single arch/x86/kernel/smp.c:267 [inline]
sysvec_call_function_single+0xa3/0xc0 arch/x86/kernel/smp.c:267
asm_sysvec_call_function_single+0x1a/0x20 arch/x86/include/asm/idtentry.h:681
Memory state around the buggy address:
ffff8881bc3ceb80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8881bc3cec00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff8881bc3cec80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
ffff8881bc3ced00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8881bc3ced80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================
***
KASAN: use-after-free Read in tcp_v6_send_response
tree: net
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git
base: 1d2929d0850fff683b8aff051275945e65f082c8
arch: amd64
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
config: https://ci.syzbot.org/builds/19ac2ebf-5913-40a0-982b-446415180382/config
syz repro: https://ci.syzbot.org/findings/e7a2188a-bd9d-4259-856a-ad2e7415f5e1/syz_repro
==================================================================
BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:82 [inline]
BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline]
BUG: KASAN: use-after-free in inet_sk_flowi_flags include/net/inet_sock.h:411 [inline]
BUG: KASAN: use-after-free in tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983
Read of size 8 at addr ffff888169a4a248 by task syz.0.28/5835
CPU: 1 UID: 0 PID: 5835 Comm: syz.0.28 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Call Trace:
<IRQ>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
check_region_inline mm/kasan/generic.c:-1 [inline]
kasan_check_range+0x264/0x2c0 mm/kasan/generic.c:200
instrument_atomic_read include/linux/instrumented.h:82 [inline]
_test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline]
inet_sk_flowi_flags include/net/inet_sock.h:411 [inline]
tcp_v6_send_response+0x116c/0x1e30 net/ipv6/tcp_ipv6.c:983
tcp_v6_send_ack net/ipv6/tcp_ipv6.c:1149 [inline]
tcp_v6_timewait_ack+0x2c6/0x4c0 net/ipv6/tcp_ipv6.c:1201
tcp_v6_rcv+0x1f09/0x2d90 net/ipv6/tcp_ipv6.c:1993
ip6_protocol_deliver_rcu+0xab9/0x1680 net/ipv6/ip6_input.c:479
ip6_input_finish+0x191/0x370 net/ipv6/ip6_input.c:534
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
ip6_input+0x16a/0x270 net/ipv6/ip6_input.c:545
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
__netif_receive_skb_one_core net/core/dev.c:6264 [inline]
__netif_receive_skb net/core/dev.c:6377 [inline]
process_backlog+0x795/0x18b0 net/core/dev.c:6728
__napi_poll+0xaa/0x330 net/core/dev.c:7787
napi_poll net/core/dev.c:7850 [inline]
net_rx_action+0x61d/0xf50 net/core/dev.c:8007
handle_softirqs+0x226/0x860 kernel/softirq.c:645
do_softirq+0x77/0xd0 kernel/softirq.c:546
</IRQ>
<TASK>
__local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
local_bh_enable include/linux/bottom_half.h:33 [inline]
rcu_read_unlock_bh include/linux/rcupdate.h:923 [inline]
__dev_queue_xmit+0x1edc/0x3820 net/core/dev.c:4961
NF_HOOK_COND include/linux/netfilter.h:314 [inline]
ip6_output+0x337/0x540 net/ipv6/ip6_output.c:248
dst_output include/net/dst.h:471 [inline]
NF_HOOK include/linux/netfilter.h:325 [inline]
ip6_xmit+0x117f/0x1a60 net/ipv6/ip6_output.c:381
inet6_csk_xmit+0x397/0x660 net/ipv6/inet6_connection_sock.c:123
__tcp_transmit_skb+0x2640/0x47c0 net/ipv4/tcp_output.c:1717
tcp_transmit_skb net/ipv4/tcp_output.c:1734 [inline]
tcp_write_xmit+0x1bfa/0x6400 net/ipv4/tcp_output.c:3062
__tcp_push_pending_frames+0x96/0x380 net/ipv4/tcp_output.c:3245
__tcp_close+0x56e/0xe70 net/ipv4/tcp.c:3220
tcp_close+0x28/0x110 net/ipv4/tcp.c:3311
inet_release+0x143/0x190 net/ipv4/af_inet.c:442
__sock_release+0xa0/0x1f0 net/socket.c:735
sock_close+0x1c/0x30 net/socket.c:1526
__fput+0x418/0xa50 fs/file_table.c:512
task_work_run+0x1d9/0x270 kernel/task_work.c:233
resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
__exit_to_user_mode_loop kernel/entry/common.c:70 [inline]
exit_to_user_mode_loop+0x204/0x770 kernel/entry/common.c:101
__exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:336 [inline]
do_syscall_64+0x328/0x520 arch/x86/entry/syscall_64.c:89
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fb1d8b9e159
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffef2a01168 EFLAGS: 00000246 ORIG_RAX: 00000000000001b4
RAX: 0000000000000000 RBX: 00007ffef2a01250 RCX: 00007fb1d8b9e159
RDX: 0000000000000000 RSI: 000000000000001e RDI: 0000000000000003
RBP: 000000000000d50a R08: 0000000000000001 R09: 0000000000000000
R10: 0000001b31820000 R11: 0000000000000246 R12: 00007ffef2a01290
R13: 00007fb1d8e25fac R14: 000000000000d53d R15: 00007fb1d8e25fa0
</TASK>
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888169a4bc80 pfn:0x169a4a
flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff)
raw: 057ff00000000000 ffffea0005c32488 ffffea0005c32508 0000000000000000
raw: ffff888169a4bc80 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as freed
page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5565, tgid 5565 (sshd), ts 40657811568
set_page_owner include/linux/page_owner.h:33 [inline]
post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1871
prep_new_page mm/page_alloc.c:1879 [inline]
get_page_from_freelist+0x2209/0x2280 mm/page_alloc.c:3943
__alloc_frozen_pages_noprof+0x217/0x5a0 mm/page_alloc.c:5436
alloc_slab_page mm/slub.c:3347 [inline]
allocate_slab+0x7d/0x620 mm/slub.c:3462
new_slab mm/slub.c:3513 [inline]
refill_objects+0x2d5/0x350 mm/slub.c:7410
refill_sheaf mm/slub.c:2885 [inline]
__pcs_replace_empty_main+0x2c8/0x6c0 mm/slub.c:4774
alloc_from_pcs mm/slub.c:4850 [inline]
slab_alloc_node mm/slub.c:4984 [inline]
kmem_cache_alloc_noprof+0x399/0x600 mm/slub.c:5010
skb_clone+0x212/0x3a0 net/core/skbuff.c:2119
dev_queue_xmit_nit+0x28d/0xac0 net/core/dev.c:2600
xmit_one net/core/dev.c:3933 [inline]
dev_hard_start_xmit+0x1c1/0x830 net/core/dev.c:3953
sch_direct_xmit+0x257/0x4c0 net/sched/sch_generic.c:372
__dev_xmit_skb net/core/dev.c:4262 [inline]
__dev_queue_xmit+0x177f/0x3820 net/core/dev.c:4884
dev_queue_xmit include/linux/netdevice.h:3461 [inline]
neigh_hh_output include/net/neighbour.h:544 [inline]
neigh_output include/net/neighbour.h:558 [inline]
ip_finish_output2+0xbda/0x10b0 net/ipv4/ip_output.c:236
NF_HOOK_COND include/linux/netfilter.h:314 [inline]
ip_output+0x29f/0x450 net/ipv4/ip_output.c:437
__ip_queue_xmit+0x10df/0x1b10 net/ipv4/ip_output.c:533
__tcp_transmit_skb+0x2d18/0x47c0 net/ipv4/tcp_output.c:1717
page last free pid 5040 tgid 5040 ts 54399149504 stack trace:
reset_page_owner include/linux/page_owner.h:26 [inline]
__free_pages_prepare mm/page_alloc.c:1418 [inline]
__free_frozen_pages+0xc93/0xd90 mm/page_alloc.c:2962
__slab_free+0x274/0x2c0 mm/slub.c:5815
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
kasan_slab_alloc include/linux/kasan.h:253 [inline]
slab_post_alloc_hook mm/slub.c:4683 [inline]
slab_alloc_node mm/slub.c:4996 [inline]
__do_kmalloc_node mm/slub.c:5413 [inline]
__kvmalloc_node_noprof+0x49f/0x820 mm/slub.c:7005
seq_buf_alloc fs/seq_file.c:39 [inline]
seq_read_iter+0x1ea/0xca0 fs/seq_file.c:211
new_sync_read fs/read_write.c:493 [inline]
vfs_read+0x595/0xa80 fs/read_write.c:574
ksys_read+0x150/0x270 fs/read_write.c:716
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Memory state around the buggy address:
ffff888169a4a100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888169a4a180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff888169a4a200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff888169a4a280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff888169a4a300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
To test a fix for this bug, please reply with `#syz test`
(on a separate line) and attach the patch to the email.
Notes:
- The patch will be applied on top of the tested series (as an
incremental fix).
- To test a new version of the whole series, please send it directly
to syzbot@lists.linux.dev.
- Arguments like custom git repos and branches are not supported.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] net/ipv6: don't route packets with unknown source address
2026-09-01 17:32 ` Matthieu Baerts
@ 2026-09-02 10:08 ` Íñigo Huguet
0 siblings, 0 replies; 5+ messages in thread
From: Íñigo Huguet @ 2026-09-02 10:08 UTC (permalink / raw)
To: Matthieu Baerts
Cc: Íñigo Huguet, David Ahern, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell,
Ido Schimmel, Pablo Neira Ayuso, Florian Westphal,
Willem de Bruijn, Simon Horman, Kuniyuki Iwashima, Phil Sutter,
Daniel Borkmann, Fernando Fernandez Mancera, Alexei Starovoitov,
Junseo Lim, Leon Hwang, Xuanqiang Luo, Willem de Bruijn,
Kees Cook, Qi Tang, Jeff Layton, Joe Damato, Breno Leitao,
Li RongQing, open list:VRF, open list, open list:NETFILTER,
open list:NETFILTER,
open list:BPF [MISC] :Keyword:(?:b|_)bpf(?:b|_)
On Tue, Sep 1, 2026 at 7:41 PM Matthieu Baerts <matttbe@kernel.org> wrote:
> Thank you for looking at this, but I think your patch is causing
> multiple KASAN warnings, e.g.
>
> https://netdev-ctrl.bots.linux.dev/logs/vmksft/net-extra-dbg/results/804584/24-connect-deny-ipv6/stderr
>
> And a few more, see:
>
> https://netdev.bots.linux.dev/branch_deltas/net-next-2026-09-01--15-01.html
As far as I can see all the warnings are in the tcp_v6_send_response
function. I guess that sk may be a request socket there, so it's not
valid to treat it as a inet_sk in all cases. I will send a v2 with the
fix.
Thanks!
--
Íñigo Huguet
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] net/ipv6: don't route packets with unknown source address
2026-09-01 11:50 [PATCH net] net/ipv6: don't route packets with unknown source address Íñigo Huguet
2026-09-01 17:32 ` Matthieu Baerts
2026-09-02 6:43 ` [syzbot ci] " syzbot ci
@ 2026-09-02 11:51 ` sashiko-bot
2 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-02 11:51 UTC (permalink / raw)
To: Íñigo Huguet; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] tcp_v6_send_response() calls inet_sk_flowi_flags() on TIME_WAIT sockets, resulting in an out-of-bounds memory read.
- [High] ip6_route_me_harder() incorrectly checks the destination address type instead of the source address type, zeroing the source address for multicast packets and bypassing security checks for unicast.
- [High] IPv6 SCTP transparent sockets are broken because FLOWI_FLAG_ANYSRC is not set during route lookup.
- [High] tcp_v6_connect() overwrites flowi6_flags, inadvertently dropping FLOWI_FLAG_ANYSRC for transparent sockets when multipath routing is enabled.
--
commit 4450c087e2afc1b6d2ec6336ee396246ee37e850
Author: Íñigo Huguet <ihuguet@riseup.net>
net/ipv6: don't route packets with unknown source address
Don't allow routing packets with a source address that is not configured
in the host. Allow it only in certain cases like when using a
transparent socket, by setting the ANYSRC flag in flowi_flags.
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 8fc4766c8da90..57eebe347902b 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -1191,6 +1191,34 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
> if (err)
> goto out_err_release;
>
> + /* Routing packets with a source address not present in the host is
> + * disallowed unless the ANYSRC flag is set (i.e. with transparent sockets).
> + * The source address must be in the same L3 domain as the destination device.
> + */
> + if (!ipv6_addr_any(&fl6->saddr) &&
> + !(fl6->flowi6_flags & FLOWI_FLAG_ANYSRC)) {
[Severity: High]
Will this break IPv6 SCTP transparent sockets?
SCTP sockets using IP_TRANSPARENT with a non-local source address fail to route
packets because sctp_v6_get_dst() initializes flowi6 but does not set
flowi6_flags using inet_sk_flowi_flags(sk). As a result, the check here
rejects the packet due to the missing FLOWI_FLAG_ANYSRC flag.
[ ... ]
> diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
> index a7025ec870359..7c19ecbec112e 100644
> --- a/net/ipv6/netfilter.c
> +++ b/net/ipv6/netfilter.c
> @@ -41,6 +41,12 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
> };
> int err;
>
> + fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0;
> + if (daddr_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL))
> + fl6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
> + else
> + fl6.saddr = in6addr_any;
[Severity: High]
Does this logic mistakenly check the destination address type instead of the
source address?
Checking daddr_type here causes the source address to be zeroed out for
multicast traffic, breaking multicast routing. It also bypasses the newly
added anti-spoofing checks for unicast traffic.
[ ... ]
> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index df9c29eb5c1f4..401a1297e7dba 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -268,6 +268,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
> fl6->flowi6_mark = sk->sk_mark;
> fl6->fl6_dport = usin->sin6_port;
> fl6->fl6_sport = inet->inet_sport;
> + fl6->flowi6_flags = inet_sk_flowi_flags(sk);
> if (IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) && !fl6->fl6_sport)
> fl6->flowi6_flags = FLOWI_FLAG_ANY_SPORT;
[Severity: High]
Is it intended to overwrite flowi6_flags and drop FLOWI_FLAG_ANYSRC?
If multipath routing is enabled (CONFIG_IP_ROUTE_MULTIPATH) and no source
port is bound, FLOWI_FLAG_ANY_SPORT is assigned using = instead of |=.
This drops the FLOWI_FLAG_ANYSRC flag, causing transparent sockets to fail
routing when attempting to connect.
[ ... ]
> @@ -979,6 +980,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
> fl6.fl6_dport = t1->dest;
> fl6.fl6_sport = t1->source;
> fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
> + fl6.flowi6_flags = sk ? inet_sk_flowi_flags(sk) : 0;
[Severity: Critical]
Can this result in an out-of-bounds memory read?
Unlike the previous line which explicitly checks sk_fullsock(sk), this calls
inet_sk_flowi_flags(sk) directly. tcp_v6_send_response() can be invoked
with sk pointing to an inet_timewait_sock. inet_sk_flowi_flags() uses
inet_test_bit(TRANSPARENT, sk), casting the socket to struct inet_sock.
Since inet_timewait_sock is smaller than inet_sock, this reads past the
end of the socket allocation.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260901115021.50057-1-ihuguet@riseup.net?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-02 11:51 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 11:50 [PATCH net] net/ipv6: don't route packets with unknown source address Íñigo Huguet
2026-09-01 17:32 ` Matthieu Baerts
2026-09-02 10:08 ` Íñigo Huguet
2026-09-02 6:43 ` [syzbot ci] " syzbot ci
2026-09-02 11:51 ` [PATCH net] " sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox