* [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
@ 2026-11-09 6:59 Hyunwoo Kim
2026-11-09 7:01 ` netdev-bot+sinfo
2026-11-11 19:02 ` netdev-bot+sashiko
0 siblings, 2 replies; 4+ messages in thread
From: Hyunwoo Kim @ 2026-11-09 6:59 UTC (permalink / raw)
To: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, David S. Miller,
Jakub Kicinski, Paolo Abeni, Simon Horman, Mat Martineau
Cc: netdev, imv4bel
Commit dcc32f4f183a ("ipv6: weaken the v4mapped source check") removed
the v4mapped source address check from the IPv6 input path and moved
the TCP check to tcp_v6_conn_request(). The check is applied to SYN
packets handled by tcp_v6_conn_request(). However, an ACK that passes
SYN cookie validation is handled by cookie_v6_check() without passing
through tcp_v6_conn_request().
cookie_v6_check() initializes the IPv6 address fields of the request
socket, but not its IPv4 address fields. In the normal SYN cookie case,
inet_csk_clone_lock() copies those uninitialized IPv4 address fields
to the child socket.
The child is an AF_INET6 socket, but its remote IPv6 address is
v4mapped. sk_ehashfn() therefore uses the IPv4 address fields and TCP
ports to compute the hash. The child is then inserted into ehash with
that hash.
tcp_v4_err() uses __inet_lookup_established(), which does not exclude
AF_INET6 sockets. An ICMPv4 error can therefore find this child socket
if its quoted IPv4 tuple matches and the interface and sequence checks
pass.
For testing, the PoC used a server helper to construct an ACK with a
v4mapped source address that passed SYN cookie validation. Before
accept(), a matching ICMPv4 Fragmentation Needed message passed the
socket lookup and sequence checks in tcp_v4_err().
At that point sock_owned_by_user() returned false, so tcp_v4_err()
called tcp_v4_mtu_reduced() directly. inet_csk_rebuild_route() then
created an IPv4 rtable and cached it in the socket.
When the socket next transmitted over IPv6, ipv4_dst_check() returned
the cached rtable. ip6_xmit() then called ip6_dst_idev(), which
interpreted the rtable as struct rt6_info and read rt6i_idev. KASAN
reported a read of 8 bytes starting 32 bytes past the end of an rtable
object whose size was 176 bytes.
KASAN report:
BUG: KASAN: slab-out-of-bounds in ip6_xmit+0x119/0xb10
Read of size 8 at addr ffff88810356a9d0 by task target-server/79
...
Call Trace:
<TASK>
...
ip6_xmit+0x119/0xb10
...
inet6_csk_xmit+0x124/0x1d0
__tcp_transmit_skb+0xda0/0x1be0
...
tcp_write_xmit+0x985/0x2f80
__tcp_push_pending_frames+0x5a/0x150
tcp_sendmsg_locked+0xe7f/0x1b60
...
</TASK>
...
Allocated by task 0:
...
dst_alloc+0x52/0x250
rt_dst_alloc+0x33/0x170
ip_route_output_key_hash_rcu+0x6df/0xe20
ip_route_output_flow+0xab/0x160
inet_csk_rebuild_route+0x2a8/0x300
inet_csk_update_pmtu+0x85/0xb0
tcp_v4_mtu_reduced+0x52/0x170
tcp_v4_err+0x651/0x710
icmp_unreach+0x1c7/0x370
icmp_rcv+0x466/0x5a0
...
The buggy address belongs to the object at ffff88810356a900
which belongs to the cache rtable of size 176
The buggy address is located 32 bytes to the right of
allocated 176-byte region [ffff88810356a900, ffff88810356a9b0)
Reject v4mapped source addresses in cookie_v6_check() before creating
the child socket. As in tcp_v6_conn_request(), increment
IPSTATS_MIB_INHDRERRORS and drop the packet.
Fixes: dcc32f4f183a ("ipv6: weaken the v4mapped source check")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
net/ipv6/syncookies.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index b581cb1ee2e8a..6c5bb4bbd349c 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -189,6 +189,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
!th->ack || th->rst)
goto out;
+ if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
+ __IP6_INC_STATS(net, NULL, IPSTATS_MIB_INHDRERRORS);
+ SKB_DR_SET(reason, IP_INHDR);
+ goto out_drop;
+ }
+
if (cookie_bpf_ok(skb)) {
req = cookie_bpf_check(sk, skb);
} else {
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
2026-11-09 6:59 [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs Hyunwoo Kim
@ 2026-11-09 7:01 ` netdev-bot+sinfo
2026-11-11 19:02 ` netdev-bot+sashiko
1 sibling, 0 replies; 4+ messages in thread
From: netdev-bot+sinfo @ 2026-11-09 7:01 UTC (permalink / raw)
To: Hyunwoo Kim
Cc: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, David S. Miller,
Jakub Kicinski, Paolo Abeni, Simon Horman, Mat Martineau, netdev
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
2026-11-09 6:59 [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs Hyunwoo Kim
2026-11-09 7:01 ` netdev-bot+sinfo
@ 2026-11-11 19:02 ` netdev-bot+sashiko
2026-11-11 19:13 ` Kuniyuki Iwashima
1 sibling, 1 reply; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-11-11 19:02 UTC (permalink / raw)
To: imv4bel
Cc: edumazet, ncardwell, kuniyu, davem, kuba, pabeni, horms,
martineau, netdev
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The patch closes only the v4mapped trigger.
--
tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
This patch makes cookie_v6_check() reject ACKs whose IPv6 source address
is v4mapped, before any child socket is created. It matches the check
already done in tcp_v6_conn_request(). Before this, a SYN cookie child
with a v4mapped peer could be found by tcp_v4_err() and end up caching an
IPv4 rtable, which ip6_xmit() then used as an rt6_info.
> diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
> index b581cb1ee2e8a..6c5bb4bbd349c 100644
> --- a/net/ipv6/syncookies.c
> +++ b/net/ipv6/syncookies.c
> @@ -189,6 +189,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
> !th->ack || th->rst)
> goto out;
>
> + if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
> + __IP6_INC_STATS(net, NULL, IPSTATS_MIB_INHDRERRORS);
> + SKB_DR_SET(reason, IP_INHDR);
> + goto out_drop;
> + }
> +
> if (cookie_bpf_ok(skb)) {
> req = cookie_bpf_check(sk, skb);
> } else {
[Severity: Medium]
This closes the v4mapped case. The commit message also names the missing
IPv4 address initialization as part of the chain:
"cookie_v6_check() initializes the IPv6 address fields of the request
socket, but not its IPv4 address fields."
Is that still a problem for native IPv6 SYN cookie connections after this
patch? Further down in cookie_v6_check(), only the IPv6 fields are
written:
ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
The normal SYN path sets the IPv4 fields in tcp_v6_init_req():
ireq->ir_rmt_addr = LOOPBACK4_IPV6;
ireq->ir_loc_addr = LOOPBACK4_IPV6;
On the cookie path, the request socket comes from a slab allocation that
is not zeroed:
cookie_tcp_check()
cookie_tcp_reqsk_alloc()
inet_reqsk_alloc()
reqsk_alloc_noprof()
kmem_cache_alloc_noprof(ops->slab, GFP_ATOMIC | __GFP_NOWARN)
Neither inet_reqsk_alloc() nor cookie_tcp_reqsk_init() sets skc_daddr or
skc_rcv_saddr. inet_csk_clone_lock() then copies those fields into the
child:
newsk->sk_daddr = ireq->ir_rmt_addr;
newsk->sk_rcv_saddr = ireq->ir_loc_addr;
newinet->inet_saddr = ireq->ir_loc_addr;
Since commit a3a128f611a965 ("inet: consolidate inet_csk_clone_lock()"),
tcp_v6_syn_recv_sock() no longer writes LOOPBACK4_IPV6 into the child.
So it looks like leftover slab bytes stay in inet_daddr, inet_rcv_saddr
and inet_saddr of every AF_INET6 child created from a SYN cookie.
Both ipv6_update_options() and do_ip_setsockopt(IP_OPTIONS) branch on
that value:
inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6
Could this make icsk_ext_hdr_len and the MSS different for a SYN cookie
child than for a normally accepted IPv6 child? Could it also trigger KMSAN
uninit-value reports? The leftover bytes would also show up in the
inet_sock_set_state tracepoint and the BPF ip4 context fields.
Would it make sense to also set ir_rmt_addr and ir_loc_addr to
LOOPBACK4_IPV6 in cookie_v6_check(), as tcp_v6_init_req() does? That
would be in addition to the v4mapped rejection, not a replacement for it.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/avFvW7nn7GIZmZ-a%40v4bel
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
2026-11-11 19:02 ` netdev-bot+sashiko
@ 2026-11-11 19:13 ` Kuniyuki Iwashima
0 siblings, 0 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2026-11-11 19:13 UTC (permalink / raw)
To: netdev-bot+sashiko
Cc: imv4bel, edumazet, ncardwell, davem, kuba, pabeni, horms,
martineau, netdev
On Wed, Nov 11, 2026 at 11:02 AM <netdev-bot+sashiko@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 1 · Low: 0
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
>
> - [Medium] The patch closes only the v4mapped trigger.
>
> --
>
> tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs
>
> This patch makes cookie_v6_check() reject ACKs whose IPv6 source address
> is v4mapped, before any child socket is created. It matches the check
> already done in tcp_v6_conn_request(). Before this, a SYN cookie child
> with a v4mapped peer could be found by tcp_v4_err() and end up caching an
> IPv4 rtable, which ip6_xmit() then used as an rt6_info.
>
> > diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
> > index b581cb1ee2e8a..6c5bb4bbd349c 100644
> > --- a/net/ipv6/syncookies.c
> > +++ b/net/ipv6/syncookies.c
> > @@ -189,6 +189,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
> > !th->ack || th->rst)
> > goto out;
> >
> > + if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
> > + __IP6_INC_STATS(net, NULL, IPSTATS_MIB_INHDRERRORS);
> > + SKB_DR_SET(reason, IP_INHDR);
> > + goto out_drop;
> > + }
> > +
> > if (cookie_bpf_ok(skb)) {
> > req = cookie_bpf_check(sk, skb);
> > } else {
>
> [Severity: Medium]
> This closes the v4mapped case. The commit message also names the missing
> IPv4 address initialization as part of the chain:
>
> "cookie_v6_check() initializes the IPv6 address fields of the request
> socket, but not its IPv4 address fields."
>
> Is that still a problem for native IPv6 SYN cookie connections after this
> patch? Further down in cookie_v6_check(), only the IPv6 fields are
> written:
>
> ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
> ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
>
> The normal SYN path sets the IPv4 fields in tcp_v6_init_req():
>
> ireq->ir_rmt_addr = LOOPBACK4_IPV6;
> ireq->ir_loc_addr = LOOPBACK4_IPV6;
>
> On the cookie path, the request socket comes from a slab allocation that
> is not zeroed:
>
> cookie_tcp_check()
> cookie_tcp_reqsk_alloc()
> inet_reqsk_alloc()
> reqsk_alloc_noprof()
> kmem_cache_alloc_noprof(ops->slab, GFP_ATOMIC | __GFP_NOWARN)
>
> Neither inet_reqsk_alloc() nor cookie_tcp_reqsk_init() sets skc_daddr or
> skc_rcv_saddr. inet_csk_clone_lock() then copies those fields into the
> child:
>
> newsk->sk_daddr = ireq->ir_rmt_addr;
> newsk->sk_rcv_saddr = ireq->ir_loc_addr;
> newinet->inet_saddr = ireq->ir_loc_addr;
>
> Since commit a3a128f611a965 ("inet: consolidate inet_csk_clone_lock()"),
> tcp_v6_syn_recv_sock() no longer writes LOOPBACK4_IPV6 into the child.
> So it looks like leftover slab bytes stay in inet_daddr, inet_rcv_saddr
> and inet_saddr of every AF_INET6 child created from a SYN cookie.
>
> Both ipv6_update_options() and do_ip_setsockopt(IP_OPTIONS) branch on
> that value:
>
> inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6
>
> Could this make icsk_ext_hdr_len and the MSS different for a SYN cookie
> child than for a normally accepted IPv6 child? Could it also trigger KMSAN
> uninit-value reports? The leftover bytes would also show up in the
> inet_sock_set_state tracepoint and the BPF ip4 context fields.
>
> Would it make sense to also set ir_rmt_addr and ir_loc_addr to
> LOOPBACK4_IPV6 in cookie_v6_check(), as tcp_v6_init_req() does? That
> would be in addition to the v4mapped rejection, not a replacement for it.
I have two patches in my queue for syncookie bugs, and one addresses this.
I'll post them later today.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-11 19:13 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09 6:59 [PATCH net] tcp: reject v4mapped source addresses in IPv6 SYN cookie ACKs Hyunwoo Kim
2026-11-09 7:01 ` netdev-bot+sinfo
2026-11-11 19:02 ` netdev-bot+sashiko
2026-11-11 19:13 ` Kuniyuki Iwashima
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox