Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebf6c9cb authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

ipv6: tcp: add a missing tcp_v6_restore_cb()



Dmitry reported use-after-free in ip6_datagram_recv_specific_ctl()

A similar bug was fixed in commit 8ce48623 ("ipv6: tcp: restore
IP6CB for pktoptions skbs"), but I missed another spot.

tcp_v6_syn_recv_sock() can indeed set np->pktoptions from ireq->pktopts

Fixes: 971f10ec ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7892032c
Loading
Loading
Loading
Loading
+13 −11
Original line number Diff line number Diff line
@@ -991,6 +991,16 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
	return 0; /* don't send reset */
}

static void tcp_v6_restore_cb(struct sk_buff *skb)
{
	/* We need to move header back to the beginning if xfrm6_policy_check()
	 * and tcp_v6_fill_cb() are going to be called again.
	 * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
	 */
	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
		sizeof(struct inet6_skb_parm));
}

static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
					 struct request_sock *req,
					 struct dst_entry *dst,
@@ -1182,10 +1192,12 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
						      sk_gfp_mask(sk, GFP_ATOMIC));
			consume_skb(ireq->pktopts);
			ireq->pktopts = NULL;
			if (newnp->pktoptions)
			if (newnp->pktoptions) {
				tcp_v6_restore_cb(newnp->pktoptions);
				skb_set_owner_r(newnp->pktoptions, newsk);
			}
		}
	}

	return newsk;

@@ -1198,16 +1210,6 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
	return NULL;
}

static void tcp_v6_restore_cb(struct sk_buff *skb)
{
	/* We need to move header back to the beginning if xfrm6_policy_check()
	 * and tcp_v6_fill_cb() are going to be called again.
	 * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
	 */
	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
		sizeof(struct inet6_skb_parm));
}

/* The socket must have it's spinlock held when we get
 * here, unless it is a TCP_LISTEN socket.
 *