[XFRM]: Always release dst_entry on error in xfrm_lookup
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								cf0b450cd5
							
						
					
				
			
			
				commit
				
					
						e104411b82
					
				
			
		
					 9 changed files with 18 additions and 48 deletions
				
			
		| 
						 | 
				
			
			@ -92,10 +92,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb,
 | 
			
		|||
	fl.fl_ip_sport = tcph->dest;
 | 
			
		||||
	fl.fl_ip_dport = tcph->source;
 | 
			
		||||
 | 
			
		||||
	if (xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0)) {
 | 
			
		||||
		dst_release(&rt->u.dst);
 | 
			
		||||
		rt = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
 | 
			
		||||
 | 
			
		||||
	return rt;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -175,10 +175,8 @@ ipv4_connected:
 | 
			
		|||
	if (final_p)
 | 
			
		||||
		ipv6_addr_copy(&fl.fl6_dst, final_p);
 | 
			
		||||
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* source address lookup done in ip6_dst_lookup */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -374,7 +374,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 | 
			
		|||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 | 
			
		||||
		goto out_dst_release;
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (ipv6_addr_is_multicast(&fl.fl6_dst))
 | 
			
		||||
		hlimit = np->mcast_hops;
 | 
			
		||||
| 
						 | 
				
			
			@ -469,7 +469,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 | 
			
		|||
	if (err)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 | 
			
		||||
		goto out_dst_release;
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (ipv6_addr_is_multicast(&fl.fl6_dst))
 | 
			
		||||
		hlimit = np->mcast_hops;
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +505,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 | 
			
		|||
out_put: 
 | 
			
		||||
	if (likely(idev != NULL))
 | 
			
		||||
		in6_dev_put(idev);
 | 
			
		||||
out_dst_release:
 | 
			
		||||
	dst_release(dst);
 | 
			
		||||
out: 
 | 
			
		||||
	icmpv6_xmit_unlock();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -447,10 +447,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	err = xfrm_lookup(&dst, &fl, NULL, 0);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (inc_opt) {
 | 
			
		||||
		if (dev->addr_len)
 | 
			
		||||
| 
						 | 
				
			
			@ -539,10 +537,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	err = xfrm_lookup(&dst, &fl, NULL, 0);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 | 
			
		||||
	send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
 | 
			
		||||
| 
						 | 
				
			
			@ -616,10 +612,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	err = xfrm_lookup(&dst, &fl, NULL, 0);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	len = sizeof(struct icmp6hdr);
 | 
			
		||||
	if (dev->addr_len)
 | 
			
		||||
| 
						 | 
				
			
			@ -1353,10 +1347,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	err = xfrm_lookup(&dst, &fl, NULL, 0);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rt = (struct rt6_info *) dst;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,11 +100,8 @@ static void send_reset(struct sk_buff *oldskb)
 | 
			
		|||
	dst = ip6_route_output(NULL, &fl);
 | 
			
		||||
	if (dst == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	if (dst->error ||
 | 
			
		||||
	    xfrm_lookup(&dst, &fl, NULL, 0)) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hh_len = (dst->dev->hard_header_len + 15)&~15;
 | 
			
		||||
	nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -782,10 +782,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 | 
			
		|||
	if (final_p)
 | 
			
		||||
		ipv6_addr_copy(&fl.fl6_dst, final_p);
 | 
			
		||||
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hlimit < 0) {
 | 
			
		||||
		if (ipv6_addr_is_multicast(&fl.fl6_dst))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -632,10 +632,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 | 
			
		|||
	if (final_p)
 | 
			
		||||
		ipv6_addr_copy(&fl.fl6_dst, final_p);
 | 
			
		||||
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 | 
			
		||||
		goto failure;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (saddr == NULL) {
 | 
			
		||||
		saddr = &fl.fl6_src;
 | 
			
		||||
| 
						 | 
				
			
			@ -888,7 +886,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	dst_release(dst);
 | 
			
		||||
        if (opt && opt != np->opt)
 | 
			
		||||
		sock_kfree_s(sk, opt, opt->tot_len);
 | 
			
		||||
	return err;
 | 
			
		||||
| 
						 | 
				
			
			@ -1000,10 +997,8 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
 | 
			
		|||
	/* sk = NULL, but it is safe for now. RST socket required. */
 | 
			
		||||
	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
 | 
			
		||||
 | 
			
		||||
		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
 | 
			
		||||
			dst_release(buff->dst);
 | 
			
		||||
		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ip6_xmit(NULL, buff, &fl, NULL, 0);
 | 
			
		||||
		TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 | 
			
		||||
| 
						 | 
				
			
			@ -1067,10 +1062,8 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
 | 
			
		|||
	fl.fl_ip_sport = t1->source;
 | 
			
		||||
 | 
			
		||||
	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
 | 
			
		||||
		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
 | 
			
		||||
			dst_release(buff->dst);
 | 
			
		||||
		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		ip6_xmit(NULL, buff, &fl, NULL, 0);
 | 
			
		||||
		TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1733,7 +1726,6 @@ static int tcp_v6_rebuild_header(struct sock *sk)
 | 
			
		|||
 | 
			
		||||
		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 | 
			
		||||
			sk->sk_err_soft = -err;
 | 
			
		||||
			dst_release(dst);
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1786,7 +1778,6 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
 | 
			
		|||
 | 
			
		||||
		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 | 
			
		||||
			sk->sk_route_caps = 0;
 | 
			
		||||
			dst_release(dst);
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -799,10 +799,8 @@ do_udp_sendmsg:
 | 
			
		|||
	if (final_p)
 | 
			
		||||
		ipv6_addr_copy(&fl->fl6_dst, final_p);
 | 
			
		||||
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {
 | 
			
		||||
		dst_release(dst);
 | 
			
		||||
	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hlimit < 0) {
 | 
			
		||||
		if (ipv6_addr_is_multicast(&fl->fl6_dst))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -765,8 +765,8 @@ restart:
 | 
			
		|||
	switch (policy->action) {
 | 
			
		||||
	case XFRM_POLICY_BLOCK:
 | 
			
		||||
		/* Prohibit the flow */
 | 
			
		||||
		xfrm_pol_put(policy);
 | 
			
		||||
		return -EPERM;
 | 
			
		||||
		err = -EPERM;
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	case XFRM_POLICY_ALLOW:
 | 
			
		||||
		if (policy->xfrm_nr == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -782,8 +782,8 @@ restart:
 | 
			
		|||
		 */
 | 
			
		||||
		dst = xfrm_find_bundle(fl, policy, family);
 | 
			
		||||
		if (IS_ERR(dst)) {
 | 
			
		||||
			xfrm_pol_put(policy);
 | 
			
		||||
			return PTR_ERR(dst);
 | 
			
		||||
			err = PTR_ERR(dst);
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dst)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue