Commit 0178b695 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

ipv6: Copy cork options in ip6_append_data

As the options passed to ip6_append_data may be ephemeral, we need
to duplicate it for corking.  This patch applies the simplest fix
which is to memdup all the relevant bits.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 12402b5b
...@@ -1105,6 +1105,18 @@ static inline int ip6_ufo_append_data(struct sock *sk, ...@@ -1105,6 +1105,18 @@ static inline int ip6_ufo_append_data(struct sock *sk,
return err; return err;
} }
static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
gfp_t gfp)
{
return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
}
static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
gfp_t gfp)
{
return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
}
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
int offset, int len, int odd, struct sk_buff *skb), int offset, int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen, void *from, int length, int transhdrlen,
...@@ -1130,17 +1142,37 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1130,17 +1142,37 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
* setup for corking * setup for corking
*/ */
if (opt) { if (opt) {
if (np->cork.opt == NULL) { if (WARN_ON(np->cork.opt))
np->cork.opt = kmalloc(opt->tot_len, return -EINVAL;
sk->sk_allocation);
np->cork.opt = kmalloc(opt->tot_len, sk->sk_allocation);
if (unlikely(np->cork.opt == NULL)) if (unlikely(np->cork.opt == NULL))
return -ENOBUFS; return -ENOBUFS;
} else if (np->cork.opt->tot_len < opt->tot_len) {
printk(KERN_DEBUG "ip6_append_data: invalid option length\n"); np->cork.opt->tot_len = opt->tot_len;
return -EINVAL; np->cork.opt->opt_flen = opt->opt_flen;
} np->cork.opt->opt_nflen = opt->opt_nflen;
memcpy(np->cork.opt, opt, opt->tot_len);
inet->cork.flags |= IPCORK_OPT; np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
sk->sk_allocation);
if (opt->dst0opt && !np->cork.opt->dst0opt)
return -ENOBUFS;
np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
sk->sk_allocation);
if (opt->dst1opt && !np->cork.opt->dst1opt)
return -ENOBUFS;
np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
sk->sk_allocation);
if (opt->hopopt && !np->cork.opt->hopopt)
return -ENOBUFS;
np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
sk->sk_allocation);
if (opt->srcrt && !np->cork.opt->srcrt)
return -ENOBUFS;
/* need source address above miyazawa*/ /* need source address above miyazawa*/
} }
dst_hold(&rt->u.dst); dst_hold(&rt->u.dst);
...@@ -1167,7 +1199,6 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1167,7 +1199,6 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
} else { } else {
rt = (struct rt6_info *)inet->cork.dst; rt = (struct rt6_info *)inet->cork.dst;
fl = &inet->cork.fl; fl = &inet->cork.fl;
if (inet->cork.flags & IPCORK_OPT)
opt = np->cork.opt; opt = np->cork.opt;
transhdrlen = 0; transhdrlen = 0;
exthdrlen = 0; exthdrlen = 0;
...@@ -1407,9 +1438,15 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1407,9 +1438,15 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
{ {
inet->cork.flags &= ~IPCORK_OPT; if (np->cork.opt) {
kfree(np->cork.opt->dst0opt);
kfree(np->cork.opt->dst1opt);
kfree(np->cork.opt->hopopt);
kfree(np->cork.opt->srcrt);
kfree(np->cork.opt); kfree(np->cork.opt);
np->cork.opt = NULL; np->cork.opt = NULL;
}
if (inet->cork.dst) { if (inet->cork.dst) {
dst_release(inet->cork.dst); dst_release(inet->cork.dst);
inet->cork.dst = NULL; inet->cork.dst = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment