diff options
author | Eric Dumazet <edumazet@google.com> | 2017-02-05 23:23:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-02-06 10:52:45 -0500 |
commit | ebf6c9cb23d7e56eec8575a88071dec97ad5c6e2 (patch) | |
tree | 408df47ccbf5f9ee7d12dcf9f9583b18ff0a2b30 /net/ipv6/tcp_ipv6.c | |
parent | 7892032cfe67f4bde6fc2ee967e45a8fbaf33756 (diff) |
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 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>
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 24 |
1 files changed, 13 insertions, 11 deletions
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: | |||
991 | return 0; /* don't send reset */ | 991 | return 0; /* don't send reset */ |
992 | } | 992 | } |
993 | 993 | ||
994 | static void tcp_v6_restore_cb(struct sk_buff *skb) | ||
995 | { | ||
996 | /* We need to move header back to the beginning if xfrm6_policy_check() | ||
997 | * and tcp_v6_fill_cb() are going to be called again. | ||
998 | * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. | ||
999 | */ | ||
1000 | memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, | ||
1001 | sizeof(struct inet6_skb_parm)); | ||
1002 | } | ||
1003 | |||
994 | static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, | 1004 | static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, |
995 | struct request_sock *req, | 1005 | struct request_sock *req, |
996 | struct dst_entry *dst, | 1006 | struct dst_entry *dst, |
@@ -1182,8 +1192,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * | |||
1182 | sk_gfp_mask(sk, GFP_ATOMIC)); | 1192 | sk_gfp_mask(sk, GFP_ATOMIC)); |
1183 | consume_skb(ireq->pktopts); | 1193 | consume_skb(ireq->pktopts); |
1184 | ireq->pktopts = NULL; | 1194 | ireq->pktopts = NULL; |
1185 | if (newnp->pktoptions) | 1195 | if (newnp->pktoptions) { |
1196 | tcp_v6_restore_cb(newnp->pktoptions); | ||
1186 | skb_set_owner_r(newnp->pktoptions, newsk); | 1197 | skb_set_owner_r(newnp->pktoptions, newsk); |
1198 | } | ||
1187 | } | 1199 | } |
1188 | } | 1200 | } |
1189 | 1201 | ||
@@ -1198,16 +1210,6 @@ out: | |||
1198 | return NULL; | 1210 | return NULL; |
1199 | } | 1211 | } |
1200 | 1212 | ||
1201 | static void tcp_v6_restore_cb(struct sk_buff *skb) | ||
1202 | { | ||
1203 | /* We need to move header back to the beginning if xfrm6_policy_check() | ||
1204 | * and tcp_v6_fill_cb() are going to be called again. | ||
1205 | * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. | ||
1206 | */ | ||
1207 | memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, | ||
1208 | sizeof(struct inet6_skb_parm)); | ||
1209 | } | ||
1210 | |||
1211 | /* The socket must have it's spinlock held when we get | 1213 | /* The socket must have it's spinlock held when we get |
1212 | * here, unless it is a TCP_LISTEN socket. | 1214 | * here, unless it is a TCP_LISTEN socket. |
1213 | * | 1215 | * |