ia64/linux-2.6.18-xen.hg

changeset 683:d1c94aa806f7

[UDP6]: Fix flowi clobbering

The udp6_sendmsg function uses a shared buffer to store the
flow without taking any locks. This leads to races with SMP.
This patch moves the flowi object onto the stack.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Sep 29 09:55:04 2008 +0100 (2008-09-29)
parents fba34c7b1c97
children fc1b82ca1e6a
files net/ipv6/udp.c
line diff
     1.1 --- a/net/ipv6/udp.c	Mon Sep 29 09:51:18 2008 +0100
     1.2 +++ b/net/ipv6/udp.c	Mon Sep 29 09:55:04 2008 +0100
     1.3 @@ -612,7 +612,7 @@ static int udpv6_sendmsg(struct kiocb *i
     1.4  	struct in6_addr *daddr, *final_p = NULL, final;
     1.5  	struct ipv6_txoptions *opt = NULL;
     1.6  	struct ip6_flowlabel *flowlabel = NULL;
     1.7 -	struct flowi *fl = &inet->cork.fl;
     1.8 +	struct flowi fl;
     1.9  	struct dst_entry *dst;
    1.10  	int addr_len = msg->msg_namelen;
    1.11  	int ulen = len;
    1.12 @@ -692,19 +692,19 @@ do_udp_sendmsg:
    1.13  	}
    1.14  	ulen += sizeof(struct udphdr);
    1.15  
    1.16 -	memset(fl, 0, sizeof(*fl));
    1.17 +	memset(&fl, 0, sizeof(fl));
    1.18  
    1.19  	if (sin6) {
    1.20  		if (sin6->sin6_port == 0)
    1.21  			return -EINVAL;
    1.22  
    1.23 -		fl->fl_ip_dport = sin6->sin6_port;
    1.24 +		fl.fl_ip_dport = sin6->sin6_port;
    1.25  		daddr = &sin6->sin6_addr;
    1.26  
    1.27  		if (np->sndflow) {
    1.28 -			fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
    1.29 -			if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
    1.30 -				flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
    1.31 +			fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
    1.32 +			if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
    1.33 +				flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
    1.34  				if (flowlabel == NULL)
    1.35  					return -EINVAL;
    1.36  				daddr = &flowlabel->dst;
    1.37 @@ -722,32 +722,32 @@ do_udp_sendmsg:
    1.38  		if (addr_len >= sizeof(struct sockaddr_in6) &&
    1.39  		    sin6->sin6_scope_id &&
    1.40  		    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
    1.41 -			fl->oif = sin6->sin6_scope_id;
    1.42 +			fl.oif = sin6->sin6_scope_id;
    1.43  	} else {
    1.44  		if (sk->sk_state != TCP_ESTABLISHED)
    1.45  			return -EDESTADDRREQ;
    1.46  
    1.47 -		fl->fl_ip_dport = inet->dport;
    1.48 +		fl.fl_ip_dport = inet->dport;
    1.49  		daddr = &np->daddr;
    1.50 -		fl->fl6_flowlabel = np->flow_label;
    1.51 +		fl.fl6_flowlabel = np->flow_label;
    1.52  		connected = 1;
    1.53  	}
    1.54  
    1.55 -	if (!fl->oif)
    1.56 -		fl->oif = sk->sk_bound_dev_if;
    1.57 +	if (!fl.oif)
    1.58 +		fl.oif = sk->sk_bound_dev_if;
    1.59  
    1.60  	if (msg->msg_controllen) {
    1.61  		opt = &opt_space;
    1.62  		memset(opt, 0, sizeof(struct ipv6_txoptions));
    1.63  		opt->tot_len = sizeof(*opt);
    1.64  
    1.65 -		err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
    1.66 +		err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
    1.67  		if (err < 0) {
    1.68  			fl6_sock_release(flowlabel);
    1.69  			return err;
    1.70  		}
    1.71 -		if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
    1.72 -			flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
    1.73 +		if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
    1.74 +			flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
    1.75  			if (flowlabel == NULL)
    1.76  				return -EINVAL;
    1.77  		}
    1.78 @@ -761,37 +761,37 @@ do_udp_sendmsg:
    1.79  		opt = fl6_merge_options(&opt_space, flowlabel, opt);
    1.80  	opt = ipv6_fixup_options(&opt_space, opt);
    1.81  
    1.82 -	fl->proto = IPPROTO_UDP;
    1.83 -	ipv6_addr_copy(&fl->fl6_dst, daddr);
    1.84 -	if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr))
    1.85 -		ipv6_addr_copy(&fl->fl6_src, &np->saddr);
    1.86 -	fl->fl_ip_sport = inet->sport;
    1.87 +	fl.proto = IPPROTO_UDP;
    1.88 +	ipv6_addr_copy(&fl.fl6_dst, daddr);
    1.89 +	if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
    1.90 +		ipv6_addr_copy(&fl.fl6_src, &np->saddr);
    1.91 +	fl.fl_ip_sport = inet->sport;
    1.92  	
    1.93  	/* merge ip6_build_xmit from ip6_output */
    1.94  	if (opt && opt->srcrt) {
    1.95  		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
    1.96 -		ipv6_addr_copy(&final, &fl->fl6_dst);
    1.97 -		ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
    1.98 +		ipv6_addr_copy(&final, &fl.fl6_dst);
    1.99 +		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
   1.100  		final_p = &final;
   1.101  		connected = 0;
   1.102  	}
   1.103  
   1.104 -	if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) {
   1.105 -		fl->oif = np->mcast_oif;
   1.106 +	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
   1.107 +		fl.oif = np->mcast_oif;
   1.108  		connected = 0;
   1.109  	}
   1.110  
   1.111 -	err = ip6_sk_dst_lookup(sk, &dst, fl);
   1.112 +	err = ip6_sk_dst_lookup(sk, &dst, &fl);
   1.113  	if (err)
   1.114  		goto out;
   1.115  	if (final_p)
   1.116 -		ipv6_addr_copy(&fl->fl6_dst, final_p);
   1.117 +		ipv6_addr_copy(&fl.fl6_dst, final_p);
   1.118  
   1.119 -	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
   1.120 +	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
   1.121  		goto out;
   1.122  
   1.123  	if (hlimit < 0) {
   1.124 -		if (ipv6_addr_is_multicast(&fl->fl6_dst))
   1.125 +		if (ipv6_addr_is_multicast(&fl.fl6_dst))
   1.126  			hlimit = np->mcast_hops;
   1.127  		else
   1.128  			hlimit = np->hop_limit;
   1.129 @@ -827,7 +827,7 @@ back_from_confirm:
   1.130  do_append_data:
   1.131  	up->len += ulen;
   1.132  	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
   1.133 -		sizeof(struct udphdr), hlimit, tclass, opt, fl,
   1.134 +		sizeof(struct udphdr), hlimit, tclass, opt, &fl,
   1.135  		(struct rt6_info*)dst,
   1.136  		corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
   1.137  	if (err)