History

bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() internals

With this patch the internal use of the skb_trimmed is reduced to the ICMPv6/IGMP checksum verification. And for the length checks the newly introduced helper functions are used instead of calculating and checking with skb->len directly. These changes should hopefully make it easier to verify that length checks are performed properly.

Linus Lüssing committed 7 years ago

Commit a2e2ca31 parent ba5ea612 files · +52 −61Browse files

Unified · Split

2 files
  1. net/ipv4/igmp.c +22 −29
  2. net/ipv6/mcast_snoop.c +30 −32
net/ipv4/igmp.c+22−29
@@ -1493,22 +1493,22 @@ static int ip_mc_check_igmp_reportv3(struct sk_buff *skb) · 1492 unmodified lines
14931493
14941494 len += sizeof(struct igmpv3_report);
14951495
1496− return pskb_may_pull(skb, len) ? 0 : -EINVAL;
1496+ return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
14971497 }
14981498
14991499 static int ip_mc_check_igmp_query(struct sk_buff *skb)
15001500 {
1501− unsigned int len = skb_transport_offset(skb);
1502−
1503− len += sizeof(struct igmphdr);
1504− if (skb->len < len)
1505− return -EINVAL;
1501+ unsigned int transport_len = ip_transport_len(skb);
1502+ unsigned int len;
15061503
15071504 /* IGMPv{1,2}? */
1508− if (skb->len != len) {
1505+ if (transport_len != sizeof(struct igmphdr)) {
15091506 /* or IGMPv3? */
1510− len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
1511− if (skb->len < len || !pskb_may_pull(skb, len))
1507+ if (transport_len < sizeof(struct igmpv3_query))
1508+ return -EINVAL;
1509+
1510+ len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
1511+ if (!ip_mc_may_pull(skb, len))
15121512 return -EINVAL;
15131513 }
15141514
@@ -1544,35 +1544,24 @@ static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) · 29 unmodified lines
15441544 return skb_checksum_simple_validate(skb);
15451545 }
15461546
1547−static int __ip_mc_check_igmp(struct sk_buff *skb)
1548−
1547+static int ip_mc_check_igmp_csum(struct sk_buff *skb)
15491548 {
1550− struct sk_buff *skb_chk;
1551− unsigned int transport_len;
15521549 unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
1553− int ret = -EINVAL;
1550+ unsigned int transport_len = ip_transport_len(skb);
1551+ struct sk_buff *skb_chk;
15541552
1555− transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
1553+ if (!ip_mc_may_pull(skb, len))
1554+ return -EINVAL;
15561555
15571556 skb_chk = skb_checksum_trimmed(skb, transport_len,
15581557 ip_mc_validate_checksum);
15591558 if (!skb_chk)
1560− goto err;
1561−
1562− if (!pskb_may_pull(skb_chk, len))
1563− goto err;
1564−
1565− ret = ip_mc_check_igmp_msg(skb_chk);
1566− if (ret)
1567− goto err;
1568−
1569− ret = 0;
1559+ return -EINVAL;
15701560
1571−err:
1572− if (skb_chk && skb_chk != skb)
1561+ if (skb_chk != skb)
15731562 kfree_skb(skb_chk);
15741563
1575− return ret;
1564+ return 0;
15761565 }
15771566
15781567 /**
@@ -1600,7 +1589,11 @@ int ip_mc_check_igmp(struct sk_buff *skb) · 21 unmodified lines
16001589 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
16011590 return -ENOMSG;
16021591
1603− return __ip_mc_check_igmp(skb);
1592+ ret = ip_mc_check_igmp_csum(skb);
1593+ if (ret < 0)
1594+ return ret;
1595+
1596+ return ip_mc_check_igmp_msg(skb);
16041597 }
16051598 EXPORT_SYMBOL(ip_mc_check_igmp);
16061599
net/ipv6/mcast_snoop.c+30−32
@@ -77,27 +77,27 @@ static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb) · 76 unmodified lines
7777
7878 len += sizeof(struct mld2_report);
7979
80− return pskb_may_pull(skb, len) ? 0 : -EINVAL;
80+ return ipv6_mc_may_pull(skb, len) ? 0 : -EINVAL;
8181 }
8282
8383 static int ipv6_mc_check_mld_query(struct sk_buff *skb)
8484 {
85+ unsigned int transport_len = ipv6_transport_len(skb);
8586 struct mld_msg *mld;
86− unsigned int len = skb_transport_offset(skb);
87+ unsigned int len;
8788
8889 /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
8990 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
9091 return -EINVAL;
9192
92− len += sizeof(struct mld_msg);
93− if (skb->len < len)
94− return -EINVAL;
95−
9693 /* MLDv1? */
97− if (skb->len != len) {
94+ if (transport_len != sizeof(struct mld_msg)) {
9895 /* or MLDv2? */
99− len += sizeof(struct mld2_query) - sizeof(struct mld_msg);
100− if (skb->len < len || !pskb_may_pull(skb, len))
96+ if (transport_len < sizeof(struct mld2_query))
97+ return -EINVAL;
98+
99+ len = skb_transport_offset(skb) + sizeof(struct mld2_query);
100+ if (!ipv6_mc_may_pull(skb, len))
101101 return -EINVAL;
102102 }
103103
@@ -115,7 +115,13 @@ static int ipv6_mc_check_mld_query(struct sk_buff *skb) · 11 unmodified lines
115115
116116 static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
117117 {
118− struct mld_msg *mld = (struct mld_msg *)skb_transport_header(skb);
118+ unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
119+ struct mld_msg *mld;
120+
121+ if (!ipv6_mc_may_pull(skb, len))
122+ return -EINVAL;
123+
124+ mld = (struct mld_msg *)skb_transport_header(skb);
119125
120126 switch (mld->mld_type) {
121127 case ICMPV6_MGM_REDUCTION:
@@ -136,36 +142,24 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb) · 14 unmodified lines
136142 return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
137143 }
138144
139−static int __ipv6_mc_check_mld(struct sk_buff *skb)
140−
145+static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
141146 {
142− struct sk_buff *skb_chk = NULL;
143− unsigned int transport_len;
144− unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
145− int ret = -EINVAL;
147+ unsigned int len = skb_transport_offset(skb) + sizeof(struct icmp6hdr);
148+ unsigned int transport_len = ipv6_transport_len(skb);
149+ struct sk_buff *skb_chk;
146150
147− transport_len = ntohs(ipv6_hdr(skb)->payload_len);
148− transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);
151+ if (!ipv6_mc_may_pull(skb, len))
152+ return -EINVAL;
149153
150154 skb_chk = skb_checksum_trimmed(skb, transport_len,
151155 ipv6_mc_validate_checksum);
152156 if (!skb_chk)
153− goto err;
154−
155− if (!pskb_may_pull(skb_chk, len))
156− goto err;
157−
158− ret = ipv6_mc_check_mld_msg(skb_chk);
159− if (ret)
160− goto err;
161−
162− ret = 0;
157+ return -EINVAL;
163158
164−err:
165− if (skb_chk && skb_chk != skb)
159+ if (skb_chk != skb)
166160 kfree_skb(skb_chk);
167161
168− return ret;
162+ return 0;
169163 }
170164
171165 /**
@@ -195,6 +189,10 @@ int ipv6_mc_check_mld(struct sk_buff *skb) · 23 unmodified lines
195189 if (ret < 0)
196190 return ret;
197191
198− return __ipv6_mc_check_mld(skb);
192+ ret = ipv6_mc_check_icmpv6(skb);
193+ if (ret < 0)
194+ return ret;
195+
196+ return ipv6_mc_check_mld_msg(skb);
199197 }
200198 EXPORT_SYMBOL(ipv6_mc_check_mld);