diff options
author | Eric Dumazet <edumazet@google.com> | 2017-02-05 23:23:22 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-18 09:11:41 -0500 |
commit | 1e340bb22af3afc881db78c17b73eaf3d26fb8fe (patch) | |
tree | 933da44e1f1594050e3d326803fa85f227fb177b | |
parent | ae1768bbbc469b75662c6714957fe5886cc960c4 (diff) |
ipv6: tcp: add a missing tcp_v6_restore_cb()
[ Upstream commit ebf6c9cb23d7e56eec8575a88071dec97ad5c6e2 ]
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 b9f1fee9a886..e5ee107a0575 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -987,6 +987,16 @@ drop: | |||
987 | return 0; /* don't send reset */ | 987 | return 0; /* don't send reset */ |
988 | } | 988 | } |
989 | 989 | ||
990 | static void tcp_v6_restore_cb(struct sk_buff *skb) | ||
991 | { | ||
992 | /* We need to move header back to the beginning if xfrm6_policy_check() | ||
993 | * and tcp_v6_fill_cb() are going to be called again. | ||
994 | * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. | ||
995 | */ | ||
996 | memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, | ||
997 | sizeof(struct inet6_skb_parm)); | ||
998 | } | ||
999 | |||
990 | static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, | 1000 | static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, |
991 | struct request_sock *req, | 1001 | struct request_sock *req, |
992 | struct dst_entry *dst, | 1002 | struct dst_entry *dst, |
@@ -1178,8 +1188,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * | |||
1178 | sk_gfp_mask(sk, GFP_ATOMIC)); | 1188 | sk_gfp_mask(sk, GFP_ATOMIC)); |
1179 | consume_skb(ireq->pktopts); | 1189 | consume_skb(ireq->pktopts); |
1180 | ireq->pktopts = NULL; | 1190 | ireq->pktopts = NULL; |
1181 | if (newnp->pktoptions) | 1191 | if (newnp->pktoptions) { |
1192 | tcp_v6_restore_cb(newnp->pktoptions); | ||
1182 | skb_set_owner_r(newnp->pktoptions, newsk); | 1193 | skb_set_owner_r(newnp->pktoptions, newsk); |
1194 | } | ||
1183 | } | 1195 | } |
1184 | } | 1196 | } |
1185 | 1197 | ||
@@ -1194,16 +1206,6 @@ out: | |||
1194 | return NULL; | 1206 | return NULL; |
1195 | } | 1207 | } |
1196 | 1208 | ||
1197 | static void tcp_v6_restore_cb(struct sk_buff *skb) | ||
1198 | { | ||
1199 | /* We need to move header back to the beginning if xfrm6_policy_check() | ||
1200 | * and tcp_v6_fill_cb() are going to be called again. | ||
1201 | * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. | ||
1202 | */ | ||
1203 | memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, | ||
1204 | sizeof(struct inet6_skb_parm)); | ||
1205 | } | ||
1206 | |||
1207 | /* The socket must have it's spinlock held when we get | 1209 | /* The socket must have it's spinlock held when we get |
1208 | * here, unless it is a TCP_LISTEN socket. | 1210 | * here, unless it is a TCP_LISTEN socket. |
1209 | * | 1211 | * |