aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-09-06 16:37:06 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-07 14:17:10 -0400
commitd679c5324d9a87c6295f56c2dea52d5f68834f41 (patch)
tree694dc71d7cdf3075237dbee0128d77897244a5e9 /net/ipv4
parente966c8ec0cd2ff97ff1d87c381e27da3c086ee35 (diff)
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>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/igmp.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 0b5580c69f2d..3479b98a00a7 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -815,14 +815,15 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
815 return 1; 815 return 1;
816} 816}
817 817
818static void igmp_heard_report(struct in_device *in_dev, __be32 group) 818/* return true if packet was dropped */
819static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
819{ 820{
820 struct ip_mc_list *im; 821 struct ip_mc_list *im;
821 822
822 /* Timers are only set for non-local groups */ 823 /* Timers are only set for non-local groups */
823 824
824 if (group == IGMP_ALL_HOSTS) 825 if (group == IGMP_ALL_HOSTS)
825 return; 826 return false;
826 827
827 rcu_read_lock(); 828 rcu_read_lock();
828 for_each_pmc_rcu(in_dev, im) { 829 for_each_pmc_rcu(in_dev, im) {
@@ -832,9 +833,11 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group)
832 } 833 }
833 } 834 }
834 rcu_read_unlock(); 835 rcu_read_unlock();
836 return false;
835} 837}
836 838
837static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, 839/* return true if packet was dropped */
840static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
838 int len) 841 int len)
839{ 842{
840 struct igmphdr *ih = igmp_hdr(skb); 843 struct igmphdr *ih = igmp_hdr(skb);
@@ -866,7 +869,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
866 /* clear deleted report items */ 869 /* clear deleted report items */
867 igmpv3_clear_delrec(in_dev); 870 igmpv3_clear_delrec(in_dev);
868 } else if (len < 12) { 871 } else if (len < 12) {
869 return; /* ignore bogus packet; freed by caller */ 872 return true; /* ignore bogus packet; freed by caller */
870 } else if (IGMP_V1_SEEN(in_dev)) { 873 } else if (IGMP_V1_SEEN(in_dev)) {
871 /* This is a v3 query with v1 queriers present */ 874 /* This is a v3 query with v1 queriers present */
872 max_delay = IGMP_Query_Response_Interval; 875 max_delay = IGMP_Query_Response_Interval;
@@ -883,13 +886,13 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
883 max_delay = 1; /* can't mod w/ 0 */ 886 max_delay = 1; /* can't mod w/ 0 */
884 } else { /* v3 */ 887 } else { /* v3 */
885 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) 888 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
886 return; 889 return true;
887 890
888 ih3 = igmpv3_query_hdr(skb); 891 ih3 = igmpv3_query_hdr(skb);
889 if (ih3->nsrcs) { 892 if (ih3->nsrcs) {
890 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) 893 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
891 + ntohs(ih3->nsrcs)*sizeof(__be32))) 894 + ntohs(ih3->nsrcs)*sizeof(__be32)))
892 return; 895 return true;
893 ih3 = igmpv3_query_hdr(skb); 896 ih3 = igmpv3_query_hdr(skb);
894 } 897 }
895 898
@@ -901,9 +904,9 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
901 in_dev->mr_qrv = ih3->qrv; 904 in_dev->mr_qrv = ih3->qrv;
902 if (!group) { /* general query */ 905 if (!group) { /* general query */
903 if (ih3->nsrcs) 906 if (ih3->nsrcs)
904 return; /* no sources allowed */ 907 return false; /* no sources allowed */
905 igmp_gq_start_timer(in_dev); 908 igmp_gq_start_timer(in_dev);
906 return; 909 return false;
907 } 910 }
908 /* mark sources to include, if group & source-specific */ 911 /* mark sources to include, if group & source-specific */
909 mark = ih3->nsrcs != 0; 912 mark = ih3->nsrcs != 0;
@@ -939,6 +942,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
939 igmp_mod_timer(im, max_delay); 942 igmp_mod_timer(im, max_delay);
940 } 943 }
941 rcu_read_unlock(); 944 rcu_read_unlock();
945 return false;
942} 946}
943 947
944/* called in rcu_read_lock() section */ 948/* called in rcu_read_lock() section */
@@ -948,6 +952,7 @@ int igmp_rcv(struct sk_buff *skb)
948 struct igmphdr *ih; 952 struct igmphdr *ih;
949 struct in_device *in_dev = __in_dev_get_rcu(skb->dev); 953 struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
950 int len = skb->len; 954 int len = skb->len;
955 bool dropped = true;
951 956
952 if (in_dev == NULL) 957 if (in_dev == NULL)
953 goto drop; 958 goto drop;
@@ -969,7 +974,7 @@ int igmp_rcv(struct sk_buff *skb)
969 ih = igmp_hdr(skb); 974 ih = igmp_hdr(skb);
970 switch (ih->type) { 975 switch (ih->type) {
971 case IGMP_HOST_MEMBERSHIP_QUERY: 976 case IGMP_HOST_MEMBERSHIP_QUERY:
972 igmp_heard_query(in_dev, skb, len); 977 dropped = igmp_heard_query(in_dev, skb, len);
973 break; 978 break;
974 case IGMP_HOST_MEMBERSHIP_REPORT: 979 case IGMP_HOST_MEMBERSHIP_REPORT:
975 case IGMPV2_HOST_MEMBERSHIP_REPORT: 980 case IGMPV2_HOST_MEMBERSHIP_REPORT:
@@ -979,7 +984,7 @@ int igmp_rcv(struct sk_buff *skb)
979 /* don't rely on MC router hearing unicast reports */ 984 /* don't rely on MC router hearing unicast reports */
980 if (skb->pkt_type == PACKET_MULTICAST || 985 if (skb->pkt_type == PACKET_MULTICAST ||
981 skb->pkt_type == PACKET_BROADCAST) 986 skb->pkt_type == PACKET_BROADCAST)
982 igmp_heard_report(in_dev, ih->group); 987 dropped = igmp_heard_report(in_dev, ih->group);
983 break; 988 break;
984 case IGMP_PIM: 989 case IGMP_PIM:
985#ifdef CONFIG_IP_PIMSM_V1 990#ifdef CONFIG_IP_PIMSM_V1
@@ -997,7 +1002,10 @@ int igmp_rcv(struct sk_buff *skb)
997 } 1002 }
998 1003
999drop: 1004drop:
1000 kfree_skb(skb); 1005 if (dropped)
1006 kfree_skb(skb);
1007 else
1008 consume_skb(skb);
1001 return 0; 1009 return 0;
1002} 1010}
1003 1011