| From ebf6c9cb23d7e56eec8575a88071dec97ad5c6e2 Mon Sep 17 00:00:00 2001 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Sun, 5 Feb 2017 20:23:22 -0800 |
| Subject: [PATCH] ipv6: tcp: add a missing tcp_v6_restore_cb() |
| |
| commit ebf6c9cb23d7e56eec8575a88071dec97ad5c6e2 upstream. |
| |
| Dmitry reported use-after-free in ip6_datagram_recv_specific_ctl() |
| |
| A similar bug was fixed in commit 8ce48623f0cf ("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: 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Reported-by: Dmitry Vyukov <dvyukov@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| |
| diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c |
| index cb8929681dc7..eaad72c3d746 100644 |
| --- a/net/ipv6/tcp_ipv6.c |
| +++ b/net/ipv6/tcp_ipv6.c |
| @@ -991,6 +991,16 @@ drop: |
| 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,8 +1192,10 @@ 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); |
| + } |
| } |
| } |
| |
| @@ -1198,16 +1210,6 @@ out: |
| 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. |
| * |
| -- |
| 2.12.0 |
| |