| From foo@baz Fri Nov 7 11:36:50 PST 2014 |
| From: Vasily Averin <vvs@parallels.com> |
| Date: Wed, 15 Oct 2014 16:24:02 +0400 |
| Subject: ipv4: dst_entry leak in ip_send_unicast_reply() |
| |
| From: Vasily Averin <vvs@parallels.com> |
| |
| [ Upstream commit 4062090e3e5caaf55bed4523a69f26c3265cc1d2 ] |
| |
| ip_setup_cork() called inside ip_append_data() steals dst entry from rt to cork |
| and in case errors in __ip_append_data() nobody frees stolen dst entry |
| |
| Fixes: 2e77d89b2fa8 ("net: avoid a pair of dst_hold()/dst_release() in ip_append_data()") |
| Signed-off-by: Vasily Averin <vvs@parallels.com> |
| Acked-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/ip_output.c | 12 +++++++++--- |
| 1 file changed, 9 insertions(+), 3 deletions(-) |
| |
| --- a/net/ipv4/ip_output.c |
| +++ b/net/ipv4/ip_output.c |
| @@ -1533,6 +1533,7 @@ void ip_send_unicast_reply(struct net *n |
| struct sk_buff *nskb; |
| struct sock *sk; |
| struct inet_sock *inet; |
| + int err; |
| |
| if (ip_options_echo(&replyopts.opt.opt, skb)) |
| return; |
| @@ -1572,8 +1573,13 @@ void ip_send_unicast_reply(struct net *n |
| sock_net_set(sk, net); |
| __skb_queue_head_init(&sk->sk_write_queue); |
| sk->sk_sndbuf = sysctl_wmem_default; |
| - ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, len, 0, |
| - &ipc, &rt, MSG_DONTWAIT); |
| + err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, |
| + len, 0, &ipc, &rt, MSG_DONTWAIT); |
| + if (unlikely(err)) { |
| + ip_flush_pending_frames(sk); |
| + goto out; |
| + } |
| + |
| nskb = skb_peek(&sk->sk_write_queue); |
| if (nskb) { |
| if (arg->csumoffset >= 0) |
| @@ -1585,7 +1591,7 @@ void ip_send_unicast_reply(struct net *n |
| skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb)); |
| ip_push_pending_frames(sk, &fl4); |
| } |
| - |
| +out: |
| put_cpu_var(unicast_sock); |
| |
| ip_rt_put(rt); |