Message ID | 1341199140-17135-1-git-send-email-roy.qing.li@gmail.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: roy.qing.li@gmail.com Date: Mon, 2 Jul 2012 11:18:59 +0800 > - if (opt) { > - newnp->opt = ipv6_dup_options(newsk, opt); > - if (opt != np->opt) > - sock_kfree_s(sk, opt, opt->tot_len); This is bogus, if we copy the options into a new copy in ipv6_dup_options() we have to free the old one or else we leak it. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
2012/7/2 David Miller <davem@davemloft.net>: > From: roy.qing.li@gmail.com > Date: Mon, 2 Jul 2012 11:18:59 +0800 > >> - if (opt) { >> - newnp->opt = ipv6_dup_options(newsk, opt); >> - if (opt != np->opt) >> - sock_kfree_s(sk, opt, opt->tot_len); > > This is bogus, if we copy the options into a new copy in > ipv6_dup_options() we have to free the old one or else we > leak it. Do you mean I should free newnp->opt firstly ? If I understand it right, I think we do not need to free it. the process is below: newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst); .. newnp = inet6_sk(newsk); .. memcpy(newnp, np, sizeof(struct ipv6_pinfo)); .. newnp->opt = NULL; So newnp->opt is not a effective memory. Thanks. -Roy -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
From: RongQing Li <roy.qing.li@gmail.com> Date: Mon, 2 Jul 2012 13:23:09 +0800 > 2012/7/2 David Miller <davem@davemloft.net>: >> From: roy.qing.li@gmail.com >> Date: Mon, 2 Jul 2012 11:18:59 +0800 >> >>> - if (opt) { >>> - newnp->opt = ipv6_dup_options(newsk, opt); >>> - if (opt != np->opt) >>> - sock_kfree_s(sk, opt, opt->tot_len); >> >> This is bogus, if we copy the options into a new copy in >> ipv6_dup_options() we have to free the old one or else we >> leak it. > > Do you mean I should free newnp->opt firstly ? > > If I understand it right, I think we do not need to free it. the > process is below: > > newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst); > .. > newnp = inet6_sk(newsk); > .. > memcpy(newnp, np, sizeof(struct ipv6_pinfo)); > .. > newnp->opt = NULL; > > So newnp->opt is not a effective memory. ipv6_dup_options() allocates new memory for the options and this call statement assigns that new pointer to np->opt. If you do not free the old (before ipv6_dup_options()) np->opt memory here, it is lost forever. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Sun, 2012-07-01 at 20:26 -0700, David Miller wrote: > From: roy.qing.li@gmail.com > Date: Mon, 2 Jul 2012 11:18:59 +0800 > > > - if (opt) { > > - newnp->opt = ipv6_dup_options(newsk, opt); > > - if (opt != np->opt) > > - sock_kfree_s(sk, opt, opt->tot_len); > > This is bogus, if we copy the options into a new copy in > ipv6_dup_options() we have to free the old one or else we > leak it. Note that the old one is the np->opt of the listener, not the child. I dont understand how np->opt could change under us, since we have the listener socket locked. If np->opt can change under us, we are doomed and need to add refcounts. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 2012-07-02 at 10:13 +0200, Eric Dumazet wrote: > Note that the old one is the np->opt of the listener, not the child. > > I dont understand how np->opt could change under us, since we have > the listener socket locked. > > If np->opt can change under us, we are doomed and need to add refcounts. Hmm, it seems net/ipv6/udp.c uses np->opt outside of the lock_sock()/release_sock(sk) boundary. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 2012-07-02 at 11:18 +0800, roy.qing.li@gmail.com wrote: > From: RongQing.Li <roy.qing.li@gmail.com> > > opt always equals np->opts, so it is meaningless to define opt, and > check if opt does not equal np->opts and then try to free opt. > > Signed-off-by: RongQing.Li <roy.qing.li@gmail.com> > --- > net/ipv6/tcp_ipv6.c | 16 +++------------- > 1 files changed, 3 insertions(+), 13 deletions(-) Acked-by: Eric Dumazet <edumazet@google.com> -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Eric Dumazet <eric.dumazet@gmail.com> Date: Mon, 02 Jul 2012 11:07:47 +0200 > On Mon, 2012-07-02 at 11:18 +0800, roy.qing.li@gmail.com wrote: >> From: RongQing.Li <roy.qing.li@gmail.com> >> >> opt always equals np->opts, so it is meaningless to define opt, and >> check if opt does not equal np->opts and then try to free opt. >> >> Signed-off-by: RongQing.Li <roy.qing.li@gmail.com> >> --- >> net/ipv6/tcp_ipv6.c | 16 +++------------- >> 1 files changed, 3 insertions(+), 13 deletions(-) > > Acked-by: Eric Dumazet <edumazet@google.com> Ok I now understand better why these changes are correct, applied. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9c06eaf..6cc67ed 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -486,7 +486,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, struct inet6_request_sock *treq = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); struct sk_buff * skb; - struct ipv6_txoptions *opt = np->opt; int err = -ENOMEM; /* First, grab a route. */ @@ -500,13 +499,11 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, fl6->daddr = treq->rmt_addr; skb_set_queue_mapping(skb, queue_mapping); - err = ip6_xmit(sk, skb, fl6, opt, np->tclass); + err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); err = net_xmit_eval(err); } done: - if (opt && opt != np->opt) - sock_kfree_s(sk, opt, opt->tot_len); return err; } @@ -1229,7 +1226,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; - struct ipv6_txoptions *opt; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; #endif @@ -1290,7 +1286,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, } treq = inet6_rsk(req); - opt = np->opt; if (sk_acceptq_is_full(sk)) goto out_overflow; @@ -1359,11 +1354,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, but we make one more one thing there: reattach optmem to newsk. */ - if (opt) { - newnp->opt = ipv6_dup_options(newsk, opt); - if (opt != np->opt) - sock_kfree_s(sk, opt, opt->tot_len); - } + if (np->opt) + newnp->opt = ipv6_dup_options(newsk, np->opt); inet_csk(newsk)->icsk_ext_hdr_len = 0; if (newnp->opt) @@ -1410,8 +1402,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, out_overflow: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); out_nonewsk: - if (opt && opt != np->opt) - sock_kfree_s(sk, opt, opt->tot_len); dst_release(dst); out: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);