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:
Родитель
e966c8ec0c
Коммит
d679c5324d
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче