mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	igmp: avoid drop_monitor false positives
igmp should call consume_skb() for all correctly processed packets, to avoid false dropwatch/drop_monitor false positives. Reported-by: Shawn Bohrer <sbohrer@rgmadvisors.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									e966c8ec0c
								
							
						
					
					
						commit
						d679c5324d
					
				
					 1 changed files with 19 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -815,14 +815,15 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igmp_heard_report(struct in_device *in_dev, __be32 group)
 | 
			
		||||
/* return true if packet was dropped */
 | 
			
		||||
static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
 | 
			
		||||
{
 | 
			
		||||
	struct ip_mc_list *im;
 | 
			
		||||
 | 
			
		||||
	/* Timers are only set for non-local groups */
 | 
			
		||||
 | 
			
		||||
	if (group == IGMP_ALL_HOSTS)
 | 
			
		||||
		return;
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	for_each_pmc_rcu(in_dev, im) {
 | 
			
		||||
| 
						 | 
				
			
			@ -832,9 +833,11 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		||||
/* return true if packet was dropped */
 | 
			
		||||
static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		||||
	int len)
 | 
			
		||||
{
 | 
			
		||||
	struct igmphdr 		*ih = igmp_hdr(skb);
 | 
			
		||||
| 
						 | 
				
			
			@ -866,7 +869,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		|||
		/* clear deleted report items */
 | 
			
		||||
		igmpv3_clear_delrec(in_dev);
 | 
			
		||||
	} else if (len < 12) {
 | 
			
		||||
		return;	/* ignore bogus packet; freed by caller */
 | 
			
		||||
		return true;	/* ignore bogus packet; freed by caller */
 | 
			
		||||
	} else if (IGMP_V1_SEEN(in_dev)) {
 | 
			
		||||
		/* This is a v3 query with v1 queriers present */
 | 
			
		||||
		max_delay = IGMP_Query_Response_Interval;
 | 
			
		||||
| 
						 | 
				
			
			@ -883,13 +886,13 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		|||
			max_delay = 1;	/* can't mod w/ 0 */
 | 
			
		||||
	} else { /* v3 */
 | 
			
		||||
		if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
 | 
			
		||||
			return;
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		ih3 = igmpv3_query_hdr(skb);
 | 
			
		||||
		if (ih3->nsrcs) {
 | 
			
		||||
			if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
 | 
			
		||||
					   + ntohs(ih3->nsrcs)*sizeof(__be32)))
 | 
			
		||||
				return;
 | 
			
		||||
				return true;
 | 
			
		||||
			ih3 = igmpv3_query_hdr(skb);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -901,9 +904,9 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		|||
			in_dev->mr_qrv = ih3->qrv;
 | 
			
		||||
		if (!group) { /* general query */
 | 
			
		||||
			if (ih3->nsrcs)
 | 
			
		||||
				return;	/* no sources allowed */
 | 
			
		||||
				return false;	/* no sources allowed */
 | 
			
		||||
			igmp_gq_start_timer(in_dev);
 | 
			
		||||
			return;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		/* mark sources to include, if group & source-specific */
 | 
			
		||||
		mark = ih3->nsrcs != 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -939,6 +942,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 | 
			
		|||
			igmp_mod_timer(im, max_delay);
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called in rcu_read_lock() section */
 | 
			
		||||
| 
						 | 
				
			
			@ -948,6 +952,7 @@ int igmp_rcv(struct sk_buff *skb)
 | 
			
		|||
	struct igmphdr *ih;
 | 
			
		||||
	struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 | 
			
		||||
	int len = skb->len;
 | 
			
		||||
	bool dropped = true;
 | 
			
		||||
 | 
			
		||||
	if (in_dev == NULL)
 | 
			
		||||
		goto drop;
 | 
			
		||||
| 
						 | 
				
			
			@ -969,7 +974,7 @@ int igmp_rcv(struct sk_buff *skb)
 | 
			
		|||
	ih = igmp_hdr(skb);
 | 
			
		||||
	switch (ih->type) {
 | 
			
		||||
	case IGMP_HOST_MEMBERSHIP_QUERY:
 | 
			
		||||
		igmp_heard_query(in_dev, skb, len);
 | 
			
		||||
		dropped = igmp_heard_query(in_dev, skb, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case IGMP_HOST_MEMBERSHIP_REPORT:
 | 
			
		||||
	case IGMPV2_HOST_MEMBERSHIP_REPORT:
 | 
			
		||||
| 
						 | 
				
			
			@ -979,7 +984,7 @@ int igmp_rcv(struct sk_buff *skb)
 | 
			
		|||
		/* don't rely on MC router hearing unicast reports */
 | 
			
		||||
		if (skb->pkt_type == PACKET_MULTICAST ||
 | 
			
		||||
		    skb->pkt_type == PACKET_BROADCAST)
 | 
			
		||||
			igmp_heard_report(in_dev, ih->group);
 | 
			
		||||
			dropped = igmp_heard_report(in_dev, ih->group);
 | 
			
		||||
		break;
 | 
			
		||||
	case IGMP_PIM:
 | 
			
		||||
#ifdef CONFIG_IP_PIMSM_V1
 | 
			
		||||
| 
						 | 
				
			
			@ -997,7 +1002,10 @@ int igmp_rcv(struct sk_buff *skb)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
drop:
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	if (dropped)
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
	else
 | 
			
		||||
		consume_skb(skb);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue