Re: [PATCH net] net: use the full socket in sk_mc_loop()

From: Theodor Arsenij Larionov-Trichkine

Date: Thu Oct 08 2026 - 08:00:13 EST


> (Was it a public syzbot report ?)

No, this one is from a syzkaller-based fuzzer extended to target nftables.
The fuzzer reached it through an nft "dup" rule in prerouting, which
re-injects the SYN over loopback with its dst already attached, so the
martian check never sees the multicast source.

A raw IP_HDRINCL socket sending a SYN from 224.0.0.1 to an address on
a dummy device also reaches it, without nft. That is the repro in v2.

v2 with your inet_csk_route_req() check, the changelog, the trimmed
splat and the repro is here:
https://lore.kernel.org/netdev/20261008114942.1376889-1-theodorlarionov@xxxxxxxxx/

Thanks for the review,
Theodor

On Thu, Oct 8, 2026 at 2:23 PM Eric Dumazet <edumazet@xxxxxxxxxx> wrote:
>
> Le jeu. 8 oct. 2026 à 12:04, Theodor Arsenij Larionov Trichkine
> <theodorlarionov@xxxxxxxxx> a écrit :
> >
> > tcp_make_synack() sets skb->sk of a SYN-ACK to the request socket.
> > If the SYN-ACK destination is multicast, ip_mc_output() calls
> > sk_mc_loop() on it, and inet_test_bit(MC_LOOP, sk) reads inet_flags,
> > which is past the end of the smaller request_sock object.
> >
> > KASAN reports a slab-out-of-bounds (or slab-use-after-free) read in
> > sk_mc_loop() from tcp_v4_send_synack() when a SYN with a multicast
> > source address reaches a listener.
> >
>
> How does such a SYN reach a listener ?
>
> ip_route_input_slow() rejects a multicast saddr as a martian source,
> so this can not come from the wire.
>
> I guess this needs a local sender : raw socket with IP_HDRINCL, and
> the packet going through loopback, where the dst is kept
> (skb_dst_force() in loopback_xmit()), so that ip_rcv_finish_core()
> skips ip_route_input_noref().
>
> Also the SYNACK route only uses ip_mc_output() if RTCF_LOCAL is set
> and the output device is not loopback, so the SYN must target an
> address of a non loopback device, and the source must be a group
> joined on this device.
>
> Please describe this in the changelog, and include the (trimmed)
> KASAN splat, and a repro if you have one.
>
> (Was it a public syzbot report ?)
>
> > Map the socket to the full socket before reading its flags.
> >
> > Fixes: ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener")
> > Signed-off-by: Theodor Arsenij Larionov Trichkine <theodorlarionov@xxxxxxxxx>
> > ---
> > net/core/sock.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/net/core/sock.c b/net/core/sock.c
> > index e8551df8330f..1302c1e848b2 100644
> > --- a/net/core/sock.c
> > +++ b/net/core/sock.c
> > @@ -769,6 +769,7 @@ bool sk_mc_loop(const struct sock *sk)
> > {
> > if (dev_recursion_level())
> > return false;
> > + sk = sk_const_to_full_sk(sk);
> > if (!sk)
> > return true;
> > /* IPV6_ADDRFORM can change sk->sk_family under us. */
> >
>
> This only addresses the out-of-bounds read, masking the root cause.
>
> We still answer a SYN with a multicast source. With this patch the
> SYNACK is looped back depending on the listener MC_LOOP setting,
> and syncookie SYNACK (skb->sk == NULL) were already sent.
>
> tcp_v4_conn_request() only looks at the input route flags, ie the
> destination of the SYN. tcp_v4_connect() refuses RTCF_MULTICAST and
> RTCF_BROADCAST routes, I think we want the same check on the route
> used for the SYNACK.
>
> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
> index 6a30f11384547e6adaeff13a005c7ce1d316a602..aa928015cd143234d3d0c72e2b607d8347f73269
> 100644
> --- a/net/ipv4/inet_connection_sock.c
> +++ b/net/ipv4/inet_connection_sock.c
> @@ -779,6 +779,9 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
> goto no_route;
> if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
> goto route_err;
> + /* Never send a SYNACK to a broadcast or multicast destination. */
> + if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
> + goto route_err;
> rcu_read_unlock();
> return &rt->dst;
>
> pw-bot: cr