Netdev List
 help / color / mirror / Atom feed
* [PATCH net v3] udp: revalidate socket family before publishing an IPv6 cork
@ 2026-09-02  1:04 Daehyeon Ko
  2026-09-03 13:05 ` [net,v3] " netdev-bot+sashiko
  0 siblings, 1 reply; 4+ messages in thread
From: Daehyeon Ko @ 2026-09-02  1:04 UTC (permalink / raw)
  To: netdev
  Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Willem de Bruijn,
	Vladislav Yasevich, linux-kernel

udpv6_sendmsg() prepares IPv6 flow and route state before taking the socket
lock when a datagram is corked.  IPV6_ADDRFORM takes the same lock, but it
can convert the socket to AF_INET during that lockless preparation because
no cork has been published yet.

If the conversion wins, udpv6_sendmsg() can publish an AF_INET6 cork on an
AF_INET socket.  Uncorking through the IPv4 operations then writes a
20-byte IPv4 header into the 40-byte IPv6 reservation while the retained
IPv6 dst routes the skb through ip6_output().  ip6_finish_output2()
consequently consumes the unwritten 20-byte tail.

An unprivileged reproducer triggered the mixed state on 12 of 10,000
sockets.  KMSAN reported an uninitialized-value read in
ip6_finish_output2() on three fresh boots, with the allocation origin in
__alloc_skb() through __ip6_append_data().  The same process recovered the
20-byte region from the TX timestamp error queue on all three boots; one
contained recognizable nonzero stale heap data.

There is also socket state to handle before cork publication.  A sendto()
with an AF_UNSPEC address clears its explicit destination and later selects
the stored peer with connected set.  On an ADDRFORM-eligible socket with a
mapped peer and a suitable IPv6 route, ip6_sk_dst_lookup_flow() can
therefore publish an IPv6 dst in the socket cache.  A native connected send
racing a new mapped connect can reach the same store.  Revalidating only
after lock_sock() prevents the mixed cork, but does not cover the non-cork
path or undo a dst stored before conversion.

Close both orderings.  After a connected IPv6 lookup, reject a socket which
has already been converted and reset any dst the lookup may have stored.
When UDP ADDRFORM publishes the AF_INET family, reset the socket dst after
the family write.  Thus, if the send stores and checks first, the later
conversion clears the cache; if conversion and its reset happen first, the
send observes AF_INET after its store and clears it.  Keep the locked
family check before cork publication to prevent the original mixed cork.

With a mapped loopback route supplied before dropping to uid 65534 with no
capabilities, an unpatched KASAN control reached ip6_sk_dst_store_flow()
from the AF_UNSPEC send.  On patched current net, the sequential conversion
released that dst from do_ipv6_setsockopt().  Corked and non-corked races
both reached the dst store, then returned EAFNOSUPPORT when conversion won;
the converted socket's follow-up send used only udp_sendmsg().  No KASAN,
Oops, warning, or panic followed.  The concurrent mapped-connect variant
was validated from the same source ordering, but was not forced in a
dedicated runtime interleaving.

Fixes: 03485f2adcde ("udpv6: Add lockless sendmsg() support")
Closes: https://lore.kernel.org/netdev/20260825160630.1888866-1-4ncienth@gmail.com/
Link: https://lore.kernel.org/netdev/a86aa34a-8bea-46d2-a785-6c423ac00b1d@redhat.com/
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
---
Changes in v3:
- Address Paolo and Sashiko's finding that AF_UNSPEC and a concurrent mapped
  connect can publish an IPv6 socket dst before the family revalidation.
- Revalidate after a connected route lookup and reset a dst stored after an
  already completed conversion.
- Reset the UDP socket dst after ADDRFORM publishes AF_INET, covering the
  opposite store-before-convert ordering and the non-cork path.
- Retain the post-lock family check which prevents late AF_INET6 cork
  publication.
- Add route-enabled, zero-capability KASAN matrix and cork/non-cork race
  validation. The separate privileged sockmap mismatch remains out of scope.
- State that the concurrent mapped-connect variant was source-validated but
  was not forced in a dedicated runtime interleaving.

v2: https://lore.kernel.org/netdev/20260829132125.1160893-1-4ncienth@gmail.com/
v1: https://lore.kernel.org/netdev/20260825160630.1888866-1-4ncienth@gmail.com/

Testing notes:
- Build and runtime validation used x86_64. Sparse was unavailable;
  allmodconfig and multi-architecture builds were not run.
- The tested reproducer is available privately on request and is not included
  in this public AI-assisted security-fix submission.
---
 net/ipv6/ipv6_sockglue.c |  1 +
 net/ipv6/udp.c           | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index b4c977434c2e..59ca446d3156 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -611,6 +611,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 				WRITE_ONCE(sk->sk_prot, &udp_prot);
 				WRITE_ONCE(sk->sk_socket->ops, &inet_dgram_ops);
 				WRITE_ONCE(sk->sk_family, PF_INET);
+				sk_dst_reset(sk);
 			}
 
 			/* Disable all options not to allocate memory anymore,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 93478d1ad576..8ba552f1a6b2 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1705,6 +1705,12 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		dst = NULL;
 		goto out;
 	}
+	if (unlikely(connected &&
+		     READ_ONCE(sk->sk_family) != AF_INET6)) {
+		sk_dst_reset(sk);
+		err = -EAFNOSUPPORT;
+		goto out;
+	}
 
 	if (ipc6.hlimit < 0)
 		ipc6.hlimit = ip6_sk_dst_hoplimit(np, fl6, dst);
@@ -1729,6 +1735,11 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	}
 
 	lock_sock(sk);
+	if (unlikely(sk->sk_family != AF_INET6)) {
+		release_sock(sk);
+		err = -EAFNOSUPPORT;
+		goto out;
+	}
 	if (unlikely(up->pending)) {
 		/* The socket is already corked while preparing it. */
 		/* ... which is an evident application bug. --ANK */

base-commit: 70f3995830d3f1e79faa14eb0605914f778feca9
-- 
2.55.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-03 21:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02  1:04 [PATCH net v3] udp: revalidate socket family before publishing an IPv6 cork Daehyeon Ko
2026-09-03 13:05 ` [net,v3] " netdev-bot+sashiko
2026-09-03 13:22   ` Paolo Abeni
2026-09-03 21:55     ` Kuniyuki Iwashima

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox