* [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM.
@ 2026-09-04 3:35 Kuniyuki Iwashima
2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Kuniyuki Iwashima @ 2026-09-04 3:35 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
The following operations have recently received a lot of AI-driven
bug reports:
* listen() + shutdown() + connect()
* connect() + connect(AF_UNSPEC) + listen()
* setsockopt(IPV6_ADDRFORM)
They are not worth fixing by churning the fast path, so this series
disallows the transitions and removes IPV6_ADDRFORM.
https://lore.kernel.org/netdev/CANn89i+px52TtJy3S9=uHxGj3s-WueguRo1Z_4FxO=02KLmwmQ@mail.gmail.com/
https://lore.kernel.org/netdev/5832ba17-c096-4f07-aa73-2e2bb6f79856@redhat.com/
I did not add Fixes tags, but if we want to backport, the tag
would be:
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Kuniyuki Iwashima (2):
tcp: Do not allow buggy transitions between ehash and lhash2.
ipv6: Remove IPV6_ADDRFORM.
include/linux/net.h | 2 +-
include/net/inet_connection_sock.h | 1 +
net/core/sock.c | 4 +-
net/ipv4/af_inet.c | 3 --
net/ipv4/inet_connection_sock.c | 1 +
net/ipv4/inet_hashtables.c | 11 ++++
net/ipv6/af_inet6.c | 4 --
net/ipv6/ipv6_sockglue.c | 87 ------------------------------
8 files changed, 15 insertions(+), 98 deletions(-)
--
2.55.0.1003.g10538fe699-goog
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2. 2026-09-04 3:35 [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM Kuniyuki Iwashima @ 2026-09-04 3:35 ` Kuniyuki Iwashima 2026-09-04 11:32 ` Jakub Sitnicki 2026-09-07 4:19 ` netdev-bot+sashiko 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-08 1:00 ` [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM patchwork-bot+netdevbpf 2 siblings, 2 replies; 9+ messages in thread From: Kuniyuki Iwashima @ 2026-09-04 3:35 UTC (permalink / raw) To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev, Kyle Zeng, Michal Luczaj, Hyunwoo Kim The following state transitions have long been a playground for syzbot, and recently AI joined in, reporting a lot more bugs. * listen() + shutdown() + connect() * connect() + connect(AF_UNSPEC) + listen() All the fix attempts would add more code to the fast path, which is not worth it. Instead of playing whack-a-mole with these edge-case bugs, let's disallow these transitions. Note that unhashed_state is placed in the 4-byte hole after icsk_pmtu_cookie. $ pahole -C inet_connection_sock vmlinux struct inet_connection_sock { ... __u32 icsk_pmtu_cookie; /* 1208 4 */ unsigned char unhashed_state; /* 1212 1 */ /* XXX 3 bytes hole, try to pack */ Reported-by: Kyle Zeng <kylebot@openai.com> Closes: https://lore.kernel.org/netdev/20260731140512.566464-1-david.lee@trailofbits.com/ Reported-by: Michal Luczaj <mhal@rbox.co> Closes: https://lore.kernel.org/netdev/20260803-sockmap-lookup-tcp-leak-v2-0-306e025bfe66@rbox.co/ Reported-by: Hyunwoo Kim <imv4bel@gmail.com> Closes: https://lore.kernel.org/netdev/20260824033331.1084971-1-imv4bel@gmail.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> --- include/net/inet_connection_sock.h | 1 + net/ipv4/inet_connection_sock.c | 1 + net/ipv4/inet_hashtables.c | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 433c2df23076..903499581db7 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -94,6 +94,7 @@ struct inet_connection_sock { u32 icsk_rto_max; __u32 icsk_delack_max; __u32 icsk_pmtu_cookie; + unsigned char unhashed_state; const struct tcp_congestion_ops *icsk_ca_ops; const struct inet_connection_sock_af_ops *icsk_af_ops; const struct tcp_ulp_ops *icsk_ulp_ops; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6257459bcee2..560ca861b6d0 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1253,6 +1253,7 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); + newicsk->unhashed_state = 0; inet_sk_set_state(newsk, TCP_SYN_RECV); inet_clone_ulp(req, newsk, priority); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ba0faa9ae2bb..5abcb0debb27 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -803,6 +803,11 @@ int inet_hash(struct sock *sk) inet_init_ehash_secret(); WARN_ON(!sk_unhashed(sk)); + + if (unlikely(inet_csk(sk)->unhashed_state && + inet_csk(sk)->unhashed_state != TCP_LISTEN)) + return -EINVAL; + ilb2 = inet_lhash2_bucket_sk(hashinfo, sk); spin_lock(&ilb2->lock); @@ -832,6 +837,9 @@ void inet_unhash(struct sock *sk) return; sock_rps_delete_flow(sk); + + inet_csk(sk)->unhashed_state = sk->sk_state; + if (sk->sk_state == TCP_LISTEN) { struct inet_listen_hashbucket *ilb2; @@ -1058,6 +1066,9 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, int ret, i, low, high; bool local_ports; + if (unlikely(inet_csk(sk)->unhashed_state == TCP_LISTEN)) + return -EINVAL; + if (port) { local_bh_disable(); ret = check_established(death_row, sk, port, NULL, false, -- 2.55.0.1003.g10538fe699-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2. 2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima @ 2026-09-04 11:32 ` Jakub Sitnicki 2026-09-07 4:19 ` netdev-bot+sashiko 1 sibling, 0 replies; 9+ messages in thread From: Jakub Sitnicki @ 2026-09-04 11:32 UTC (permalink / raw) To: Kuniyuki Iwashima Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel, Simon Horman, Kuniyuki Iwashima, netdev, Kyle Zeng, Michal Luczaj, Hyunwoo Kim On Fri, Sep 04, 2026 at 03:35 AM GMT, Kuniyuki Iwashima wrote: > The following state transitions have long been a playground for > syzbot, and recently AI joined in, reporting a lot more bugs. > > * listen() + shutdown() + connect() > * connect() + connect(AF_UNSPEC) + listen() > > All the fix attempts would add more code to the fast path, which > is not worth it. > > Instead of playing whack-a-mole with these edge-case bugs, > let's disallow these transitions. > > Note that unhashed_state is placed in the 4-byte hole after > icsk_pmtu_cookie. > > $ pahole -C inet_connection_sock vmlinux > struct inet_connection_sock { > ... > __u32 icsk_pmtu_cookie; /* 1208 4 */ > unsigned char unhashed_state; /* 1212 1 */ > > /* XXX 3 bytes hole, try to pack */ > > Reported-by: Kyle Zeng <kylebot@openai.com> > Closes: https://lore.kernel.org/netdev/20260731140512.566464-1-david.lee@trailofbits.com/ > Reported-by: Michal Luczaj <mhal@rbox.co> > Closes: https://lore.kernel.org/netdev/20260803-sockmap-lookup-tcp-leak-v2-0-306e025bfe66@rbox.co/ > Reported-by: Hyunwoo Kim <imv4bel@gmail.com> > Closes: https://lore.kernel.org/netdev/20260824033331.1084971-1-imv4bel@gmail.com/ > Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> > --- > include/net/inet_connection_sock.h | 1 + > net/ipv4/inet_connection_sock.c | 1 + > net/ipv4/inet_hashtables.c | 11 +++++++++++ > 3 files changed, 13 insertions(+) > > diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h > index 433c2df23076..903499581db7 100644 > --- a/include/net/inet_connection_sock.h > +++ b/include/net/inet_connection_sock.h > @@ -94,6 +94,7 @@ struct inet_connection_sock { > u32 icsk_rto_max; > __u32 icsk_delack_max; > __u32 icsk_pmtu_cookie; > + unsigned char unhashed_state; > const struct tcp_congestion_ops *icsk_ca_ops; > const struct inet_connection_sock_af_ops *icsk_af_ops; > const struct tcp_ulp_ops *icsk_ulp_ops; Glad we went in that direction in the end. Makes like easier. Nit: Could be a flag, like CAN_LISTEN or CAN_CONNECT? Either INET_FLAGS_* or maybe we need ICSK_FLAGS_*? Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com> ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2. 2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima 2026-09-04 11:32 ` Jakub Sitnicki @ 2026-09-07 4:19 ` netdev-bot+sashiko 1 sibling, 0 replies; 9+ messages in thread From: netdev-bot+sashiko @ 2026-09-07 4:19 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, kuba, pabeni, ncardwell, willemb, dsahern, idosch, horms, kuni1840, netdev, 4ncienth, imv4bel Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 0 · Low: 1 - [Low] The commit carries three Reported-by/Closes pairs for concrete, user-triggerable bug reports (including a sockmap/TCP leak) but no… -- tcp: Do not allow buggy transitions between ehash and lhash2. This adds a new unhashed_state field to struct inet_connection_sock, recording sk->sk_state at inet_unhash() time, and uses it to reject listen() on a socket that was unhashed from a non-listening state and connect() on a socket that was unhashed as a listener. Closes: https://lore.kernel.org/netdev/20260731140512.566464-1-david.lee@trailofbits.com/ Closes: https://lore.kernel.org/netdev/20260803-sockmap-lookup-tcp-leak-v2-0-306e025bfe66@rbox.co/ Closes: https://lore.kernel.org/netdev/20260824033331.1084971-1-imv4bel@gmail.com/ [Severity: Low] The changelog carries three Reported-by/Closes pairs for concrete, user-triggerable reports (including the sockmap/TCP socket leak), but there is no Fixes: tag and no note about stable trees. Since the same change also tightens observable behaviour in inet_hash() and __inet_hash_connect() (listen() and connect() now return -EINVAL for sequences that previously succeeded), would it help backporters to either add a Fixes: tag, or state in the changelog why no tag is given? Without either, stable maintainers have no anchor commit and no record of the trade-off between closing the reported memory-safety issues and the new -EINVAL returns from listen()/connect(). > diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c > index ba0faa9ae2bb3..5abcb0debb270 100644 > --- a/net/ipv4/inet_hashtables.c > +++ b/net/ipv4/inet_hashtables.c > @@ -803,6 +803,11 @@ int inet_hash(struct sock *sk) > inet_init_ehash_secret(); > > WARN_ON(!sk_unhashed(sk)); > + > + if (unlikely(inet_csk(sk)->unhashed_state && > + inet_csk(sk)->unhashed_state != TCP_LISTEN)) > + return -EINVAL; > + > ilb2 = inet_lhash2_bucket_sk(hashinfo, sk); > > spin_lock(&ilb2->lock); [ ... ] > @@ -1058,6 +1066,9 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, > int ret, i, low, high; > bool local_ports; > > + if (unlikely(inet_csk(sk)->unhashed_state == TCP_LISTEN)) > + return -EINVAL; > + > if (port) { > local_bh_disable(); > ret = check_established(death_row, sk, port, NULL, false, -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260904033543.2635540-1-kuniyu%40google.com ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM. 2026-09-04 3:35 [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima @ 2026-09-04 3:35 ` Kuniyuki Iwashima 2026-09-04 9:10 ` Paolo Abeni ` (2 more replies) 2026-09-08 1:00 ` [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM patchwork-bot+netdevbpf 2 siblings, 3 replies; 9+ messages in thread From: Kuniyuki Iwashima @ 2026-09-04 3:35 UTC (permalink / raw) To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev, Daehyeon Ko, Hyunwoo Kim Recently, IPV6_ADDRFORM has received many AI-driven bug reports. Fixing them properly would needlessly churn the fast paths in TCP and UDP. IPV6_ADDRFORM was initially introduced in RFC 2133 in 1997, but only two years later, it was removed from RFC 2553 in 1999. In 2026, modern applications natively support dual-stack sockets; notably, systemd's socket activation does not use IPV6_ADDRFORM. Also, getsockopt(IPV6_ADDRFORM) can be replaced with SO_DOMAIN. Let's remove IPV6_ADDRFORM. Later, we can remove sk->sk_prot_creator and revert commit c26c192c3d48 ("udp: properly deal with xfrm encap and ADDRFORM"). Reported-by: Daehyeon Ko <4ncienth@gmail.com> Closes: https://lore.kernel.org/netdev/20260902010408.1057857-1-4ncienth@gmail.com/ Reported-by: Hyunwoo Kim <imv4bel@gmail.com> Closes: https://lore.kernel.org/netdev/20260824033331.1084971-1-imv4bel@gmail.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> --- include/linux/net.h | 2 +- net/core/sock.c | 4 +- net/ipv4/af_inet.c | 3 -- net/ipv6/af_inet6.c | 4 -- net/ipv6/ipv6_sockglue.c | 87 ---------------------------------------- 5 files changed, 2 insertions(+), 98 deletions(-) diff --git a/include/linux/net.h b/include/linux/net.h index 3d82966e2243..470100ae7107 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -166,7 +166,7 @@ struct socket { struct file *file; struct sock *sk; - const struct proto_ops *ops; /* Might change with IPV6_ADDRFORM or MPTCP. */ + const struct proto_ops *ops; /* Might change with MPTCP. */ struct socket_wq wq; }; diff --git a/net/core/sock.c b/net/core/sock.c index fa60b7494c58..1d5927cd49a1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -770,7 +770,7 @@ bool sk_mc_loop(const struct sock *sk) return false; if (!sk) return true; - /* IPV6_ADDRFORM can change sk->sk_family under us. */ + switch (READ_ONCE(sk->sk_family)) { case AF_INET: return inet_test_bit(MC_LOOP, sk); @@ -4010,7 +4010,6 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ return READ_ONCE(sk->sk_prot)->getsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(sock_common_getsockopt); @@ -4032,7 +4031,6 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ return READ_ONCE(sk->sk_prot)->setsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(sock_common_setsockopt); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 32d006c1a8ee..d9421ac38d78 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -582,7 +582,6 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr_unsized *uaddr, if (addr_len < sizeof(uaddr->sa_family)) return -EINVAL; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); if (uaddr->sa_family == AF_UNSPEC) @@ -789,7 +788,6 @@ int inet_accept(struct socket *sock, struct socket *newsock, { struct sock *sk1 = sock->sk, *sk2; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ arg->err = -EINVAL; sk2 = READ_ONCE(sk1->sk_prot)->accept(sk1, arg); if (!sk2) @@ -875,7 +873,6 @@ void inet_splice_eof(struct socket *sock) if (unlikely(inet_send_prepare(sk))) return; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); if (prot->splice_eof) prot->splice_eof(sock); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 282912a11999..f0efdc13baf4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -429,7 +429,6 @@ int inet6_bind_sk(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len) const struct proto *prot; int err = 0; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); /* If the socket has its own bind function then use it. */ if (prot->bind) @@ -567,7 +566,6 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFDSTADDR: return addrconf_set_dstaddr(net, argp); default: - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); if (!prot->ioctl) return -ENOIOCTLCMD; @@ -636,7 +634,6 @@ int inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) if (unlikely(inet_send_prepare(sk))) return -EAGAIN; - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); return INDIRECT_CALL_2(prot->sendmsg, tcp_sendmsg, udpv6_sendmsg, sk, msg, size); @@ -651,7 +648,6 @@ int inet6_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, if (likely(!(flags & MSG_ERRQUEUE))) sock_rps_record_flow(sk); - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ prot = READ_ONCE(sk->sk_prot); return INDIRECT_CALL_2(prot->recvmsg, tcp_recvmsg, udpv6_recvmsg, sk, msg, size, flags); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index b4c977434c2e..1f68fb64a43e 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -547,86 +547,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sockopt_lock_sock(sk); - /* Another thread has converted the socket into IPv4 with - * IPV6_ADDRFORM concurrently. - */ - if (unlikely(sk->sk_family != AF_INET6)) - goto unlock; - switch (optname) { - - case IPV6_ADDRFORM: - if (optlen < sizeof(int)) - goto e_inval; - if (val == PF_INET) { - if (sk->sk_type == SOCK_RAW) - break; - - if (sk->sk_protocol == IPPROTO_UDP) { - if (udp_sk(sk)->pending == AF_INET6) { - retv = -EBUSY; - break; - } - } else if (sk->sk_protocol == IPPROTO_TCP) { - if (sk->sk_prot != &tcpv6_prot) { - retv = -EBUSY; - break; - } - } else { - break; - } - - if (sk->sk_state != TCP_ESTABLISHED) { - retv = -ENOTCONN; - break; - } - - if (ipv6_only_sock(sk) || - !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - retv = -EADDRNOTAVAIL; - break; - } - - __ipv6_sock_mc_close(sk); - __ipv6_sock_ac_close(sk); - - if (sk->sk_protocol == IPPROTO_TCP) { - struct inet_connection_sock *icsk = inet_csk(sk); - - sock_prot_inuse_add(net, sk->sk_prot, -1); - sock_prot_inuse_add(net, &tcp_prot, 1); - - /* Paired with READ_ONCE(sk->sk_prot) in inet6_stream_ops */ - WRITE_ONCE(sk->sk_prot, &tcp_prot); - /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ - WRITE_ONCE(icsk->icsk_af_ops, &ipv4_specific); - WRITE_ONCE(sk->sk_socket->ops, &inet_stream_ops); - WRITE_ONCE(sk->sk_family, PF_INET); - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - } else { - sock_prot_inuse_add(net, sk->sk_prot, -1); - sock_prot_inuse_add(net, &udp_prot, 1); - - /* Paired with READ_ONCE(sk->sk_prot) in inet6_dgram_ops */ - WRITE_ONCE(sk->sk_prot, &udp_prot); - WRITE_ONCE(sk->sk_socket->ops, &inet_dgram_ops); - WRITE_ONCE(sk->sk_family, PF_INET); - } - - /* Disable all options not to allocate memory anymore, - * but there is still a race. See the lockless path - * in udpv6_sendmsg() and ipv6_local_rxpmtu(). - */ - np->rxopt.all = 0; - - inet6_cleanup_sock(sk); - - module_put(THIS_MODULE); - retv = 0; - break; - } - goto e_inval; - case IPV6_V6ONLY: if (optlen < sizeof(int) || inet_sk(sk)->inet_num) @@ -1088,14 +1009,6 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT; switch (optname) { - case IPV6_ADDRFORM: - if (sk->sk_protocol != IPPROTO_UDP && - sk->sk_protocol != IPPROTO_TCP) - return -ENOPROTOOPT; - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - val = sk->sk_family; - break; case MCAST_MSFILTER: if (in_compat_syscall()) return compat_ipv6_get_msfilter(sk, optval, optlen, len); -- 2.55.0.1003.g10538fe699-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM. 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima @ 2026-09-04 9:10 ` Paolo Abeni 2026-09-07 4:19 ` netdev-bot+sashiko 2026-09-08 9:21 ` David Laight 2 siblings, 0 replies; 9+ messages in thread From: Paolo Abeni @ 2026-09-04 9:10 UTC (permalink / raw) To: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski, Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel Cc: Simon Horman, Kuniyuki Iwashima, netdev, Daehyeon Ko, Hyunwoo Kim On 9/4/26 5:35 AM, Kuniyuki Iwashima wrote: > Recently, IPV6_ADDRFORM has received many AI-driven bug reports. > Fixing them properly would needlessly churn the fast paths in TCP > and UDP. > > IPV6_ADDRFORM was initially introduced in RFC 2133 in 1997, > but only two years later, it was removed from RFC 2553 in 1999. > > In 2026, modern applications natively support dual-stack sockets; > notably, systemd's socket activation does not use IPV6_ADDRFORM. > > Also, getsockopt(IPV6_ADDRFORM) can be replaced with SO_DOMAIN. > > Let's remove IPV6_ADDRFORM. Yes please! Acked-by: Paolo Abeni <pabeni@redhat.com> > Later, we can remove sk->sk_prot_creator and revert commit > c26c192c3d48 ("udp: properly deal with xfrm encap and ADDRFORM"). I'm not 110% sure syzkaller or others will find a way to still trigger the race addressed there, but I guess we will see. Also I guess we can get rid of several READ_ONCE(sk->sk_family). /P ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM. 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 9:10 ` Paolo Abeni @ 2026-09-07 4:19 ` netdev-bot+sashiko 2026-09-08 9:21 ` David Laight 2 siblings, 0 replies; 9+ messages in thread From: netdev-bot+sashiko @ 2026-09-07 4:19 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, kuba, pabeni, ncardwell, willemb, dsahern, idosch, horms, kuni1840, netdev, 4ncienth, imv4bel Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: Critical: 0 · High: 1 · Medium: 0 · Low: 2 - [High] Verified userspace-visible ABI removal with no deprecation path and no disclosure of the resulting errno. - [Low] The removal is incomplete: the patch cleans up the ADDRFORM comments in net/core/sock.c, net/ipv4/af_inet.c and… - [Low] security/landlock/net.c retains three comments (and one user- visible policy decision) whose entire justification is that 'sk_family… -- ipv6: Remove IPV6_ADDRFORM. This removes the IPV6_ADDRFORM socket option from both the setsockopt and getsockopt paths in net/ipv6/ipv6_sockglue.c, and drops the comments in net/core/sock.c, net/ipv4/af_inet.c, net/ipv6/af_inet6.c and include/linux/net.h that documented the sk_prot, sk_family and socket->ops mutability the option caused. The commit message notes that sk->sk_prot_creator and commit c26c192c3d48 can be cleaned up afterwards. Closes: https://lore.kernel.org/netdev/20260902010408.1057857-1-4ncienth@gmail.com/ Closes: https://lore.kernel.org/netdev/20260824033331.1084971-1-imv4bel@gmail.com/ > diff --git a/include/linux/net.h b/include/linux/net.h > index 3d82966e2243b..470100ae71077 100644 > --- a/include/linux/net.h > +++ b/include/linux/net.h > @@ -166,7 +166,7 @@ struct socket { > > struct file *file; > struct sock *sk; > - const struct proto_ops *ops; /* Might change with IPV6_ADDRFORM or MPTCP. */ > + const struct proto_ops *ops; /* Might change with MPTCP. */ > > struct socket_wq wq; > }; [Severity: Low] This hunk and the ones in net/core/sock.c, net/ipv4/af_inet.c and net/ipv6/af_inet6.c clean up the ADDRFORM comments, but a grep at this commit still finds three places whose only justification was the option. The kernel-doc for the retained sk_prot_creator field in include/net/sock.h still points at the deleted code: * @sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, * IPV6_ADDRFORM for instance) set_xfrm_gro_udp_encap_rcv() in net/ipv4/udp.c still explains its unregister branch with a feature that no longer exists: if (udp_sk(sk)->gro_receive != new_gro_receive) { /* * With IPV6_ADDRFORM the gro callback could change * after being set, unregister the old one, if valid. */ The family argument there comes from sk->sk_family, which can no longer change for a live socket, so is the remaining comment accurate? mptcp_supported_sockopt() in net/mptcp/sockopt.c still lists the option among the IPv6 options MPTCP does not support: /* IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, IPV6_UNICAST_IF, * IPV6_MULTICAST_IF, IPV6_ADDRFORM, Were these three left out on purpose? Only the udp.c one is mentioned in the commit message, as a later revert of c26c192c3d48, so it is hard to tell which leftovers are intentional. > diff --git a/net/core/sock.c b/net/core/sock.c > index fa60b7494c586..1d5927cd49a10 100644 > --- a/net/core/sock.c > +++ b/net/core/sock.c > @@ -770,7 +770,7 @@ bool sk_mc_loop(const struct sock *sk) > return false; > if (!sk) > return true; > - /* IPV6_ADDRFORM can change sk->sk_family under us. */ > + > switch (READ_ONCE(sk->sk_family)) { > case AF_INET: > return inet_test_bit(MC_LOOP, sk); [Severity: Low] Dropping this comment in sk_mc_loop() says the tree now treats sk_family as stable after socket creation, and a grep for writes to sk->sk_family agrees: the only assignments left are in sk_alloc(), the per-family create paths such as inet6_create(), and net/bpf/test_run.c on a freshly allocated socket. security/landlock/net.c was not updated the same way, so the tree now holds two contradictory statements about the same field. current_check_access_socket() still says: /* * The socket is not locked, so sk_family can change concurrently due to * e.g. setsockopt(IPV6_ADDRFORM). */ sock_family = READ_ONCE(sock->sk->sk_family); and, further down, it still denies an explicit AF_UNSPEC destination on an IPv6 UDP socket for that same reason, while conceding the operation should be permitted: * on such sockets (so it should always be * allowed). That's because the socket's family * can change under our feet (if another thread * calls setsockopt(IPV6_ADDRFORM)) to IPv4, * which would then treat AF_UNSPEC as AF_INET. */ audit_net.family = AF_UNSPEC; The bind path repeats the same rationale. Should the Landlock comments be updated in this series too, or at least called out in the commit message so whoever revisits that -EACCES knows the premise is gone? > diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c > index b4c977434c2e0..1f68fb64a43ef 100644 > --- a/net/ipv6/ipv6_sockglue.c > +++ b/net/ipv6/ipv6_sockglue.c > @@ -547,86 +547,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, > > sockopt_lock_sock(sk); > > - /* Another thread has converted the socket into IPv4 with > - * IPV6_ADDRFORM concurrently. > - */ > - if (unlikely(sk->sk_family != AF_INET6)) > - goto unlock; > - > switch (optname) { > - > - case IPV6_ADDRFORM: > - if (optlen < sizeof(int)) > - goto e_inval; > - if (val == PF_INET) { > - if (sk->sk_type == SOCK_RAW) > - break; > - [ ... ] > - /* Disable all options not to allocate memory anymore, > - * but there is still a race. See the lockless path > - * in udpv6_sendmsg() and ipv6_local_rxpmtu(). > - */ > - np->rxopt.all = 0; > - > - inet6_cleanup_sock(sk); > - > - module_put(THIS_MODULE); > - retv = 0; > - break; > - } > - goto e_inval; > - > case IPV6_V6ONLY: > if (optlen < sizeof(int) || > inet_sk(sk)->inet_num) > @@ -1088,14 +1009,6 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, > if (copy_from_sockptr(&len, optlen, sizeof(int))) > return -EFAULT; > switch (optname) { > - case IPV6_ADDRFORM: > - if (sk->sk_protocol != IPPROTO_UDP && > - sk->sk_protocol != IPPROTO_TCP) > - return -ENOPROTOOPT; > - if (sk->sk_state != TCP_ESTABLISHED) > - return -ENOTCONN; > - val = sk->sk_family; > - break; > case MCAST_MSFILTER: > if (in_compat_syscall()) > return compat_ipv6_get_msfilter(sk, optval, optlen, len); [Severity: High] Is this a user visible ABI regression that needs a deprecation step first? With the case gone from do_ipv6_setsockopt(), optname 1 matches nothing in either the lockless or the locked switch, so the function falls through to its initial value: int retv = -ENOPROTOOPT; ipv6_setsockopt() then hands optname 1 to netfilter: if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && optname != IPV6_XFRM_POLICY) err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen); No PF_INET6 sockopt handler claims optnames below IP6T_BASE_CTL (64), so setsockopt(SOL_IPV6, IPV6_ADDRFORM, &PF_INET, 4) now returns -ENOPROTOOPT where it previously converted an established v4-mapped socket, and getsockopt(SOL_IPV6, IPV6_ADDRFORM) hits the default: return -ENOPROTOOPT; arm of do_ipv6_getsockopt() where it previously returned sk->sk_family. The UAPI definition is kept: #define IPV6_ADDRFORM 1 so existing binaries keep compiling and only start failing at runtime with a generic "Protocol not available", with no pr_warn_once() naming the caller and no Kconfig or sysctl to restore the old behaviour. Could the commit message state the new errno explicitly, and say that already-built applications will fail at runtime rather than at build time? The message says "getsockopt(IPV6_ADDRFORM) can be replaced with SO_DOMAIN", which covers only the getsockopt side and still needs a recompile. Is there any suggested replacement for the setsockopt side, i.e. for the IPv6 to IPv4 socket conversion itself? Would a warn-and-deprecate cycle before the removal make this easier for whoever is still calling it? -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260904033543.2635540-1-kuniyu%40google.com ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM. 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 9:10 ` Paolo Abeni 2026-09-07 4:19 ` netdev-bot+sashiko @ 2026-09-08 9:21 ` David Laight 2 siblings, 0 replies; 9+ messages in thread From: David Laight @ 2026-09-08 9:21 UTC (permalink / raw) To: Kuniyuki Iwashima Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Willem de Bruijn, David Ahern, Ido Schimmel, Simon Horman, Kuniyuki Iwashima, netdev, Daehyeon Ko, Hyunwoo Kim On Fri, 4 Sep 2026 03:35:29 +0000 Kuniyuki Iwashima <kuniyu@google.com> wrote: > Recently, IPV6_ADDRFORM has received many AI-driven bug reports. > Fixing them properly would needlessly churn the fast paths in TCP > and UDP. > > IPV6_ADDRFORM was initially introduced in RFC 2133 in 1997, > but only two years later, it was removed from RFC 2553 in 1999. > > In 2026, modern applications natively support dual-stack sockets; > notably, systemd's socket activation does not use IPV6_ADDRFORM. > > Also, getsockopt(IPV6_ADDRFORM) can be replaced with SO_DOMAIN. > > Let's remove IPV6_ADDRFORM. How does the ipv6(7) man page get updated to match? ... > - module_put(THIS_MODULE); That wasn't good... David ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM. 2026-09-04 3:35 [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima @ 2026-09-08 1:00 ` patchwork-bot+netdevbpf 2 siblings, 0 replies; 9+ messages in thread From: patchwork-bot+netdevbpf @ 2026-09-08 1:00 UTC (permalink / raw) To: Kuniyuki Iwashima Cc: davem, edumazet, kuba, pabeni, ncardwell, willemb, dsahern, idosch, horms, kuni1840, netdev Hello: This series was applied to netdev/net-next.git (main) by Jakub Kicinski <kuba@kernel.org>: On Fri, 4 Sep 2026 03:35:27 +0000 you wrote: > The following operations have recently received a lot of AI-driven > bug reports: > > * listen() + shutdown() + connect() > * connect() + connect(AF_UNSPEC) + listen() > > * setsockopt(IPV6_ADDRFORM) > > [...] Here is the summary with links: - [v1,net-next,1/2] tcp: Do not allow buggy transitions between ehash and lhash2. https://git.kernel.org/netdev/net-next/c/8cc3aef0cb19 - [v1,net-next,2/2] ipv6: Remove IPV6_ADDRFORM. https://git.kernel.org/netdev/net-next/c/31c5ea8a3296 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-08 9:21 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-04 3:35 [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 3:35 ` [PATCH v1 net-next 1/2] tcp: Do not allow buggy transitions between ehash and lhash2 Kuniyuki Iwashima 2026-09-04 11:32 ` Jakub Sitnicki 2026-09-07 4:19 ` netdev-bot+sashiko 2026-09-04 3:35 ` [PATCH v1 net-next 2/2] ipv6: Remove IPV6_ADDRFORM Kuniyuki Iwashima 2026-09-04 9:10 ` Paolo Abeni 2026-09-07 4:19 ` netdev-bot+sashiko 2026-09-08 9:21 ` David Laight 2026-09-08 1:00 ` [PATCH v1 net-next 0/2] net: Disallow buggy TCP transitions and IPV6_ADDRFORM patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox