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
1493 1493
1494 len += sizeof(struct igmpv3_report);1494 len += sizeof(struct igmpv3_report);
1495 1495
1496 return pskb_may_pull(skb, len) ? 0 : -EINVAL;1496 return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
1497}1497}
1498 1498
1499static int ip_mc_check_igmp_query(struct sk_buff *skb)1499static int ip_mc_check_igmp_query(struct sk_buff *skb)
1500{1500{
1501 unsigned int len = skb_transport_offset(skb);1501 unsigned int transport_len = ip_transport_len(skb);
1502 1502 unsigned int len;
1503 len += sizeof(struct igmphdr);
1504 if (skb->len < len)
1505 return -EINVAL;
1506 1503
1507 /* IGMPv{1,2}? */1504 /* IGMPv{1,2}? */
1508 if (skb->len != len) {1505 if (transport_len != sizeof(struct igmphdr)) {
1509 /* or IGMPv3? */1506 /* or IGMPv3? */
1510 len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);1507 if (transport_len < sizeof(struct igmpv3_query))
1511 if (skb->len < len || !pskb_may_pull(skb, len))1508 return -EINVAL;
1509
1510 len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
1511 if (!ip_mc_may_pull(skb, len))
1512 return -EINVAL;1512 return -EINVAL;
1513 }1513 }
1514 1514
@@ -1544,35 +1544,24 @@ static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) · 29 unmodified lines
1544 return skb_checksum_simple_validate(skb);1544 return skb_checksum_simple_validate(skb);
1545}1545}
1546 1546
1547static int __ip_mc_check_igmp(struct sk_buff *skb)1547static int ip_mc_check_igmp_csum(struct sk_buff *skb)
1548
1549{1548{
1550 struct sk_buff *skb_chk;
1551 unsigned int transport_len;
1552 unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);1549 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;
1554 1552
1555 transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);1553 if (!ip_mc_may_pull(skb, len))
1554 return -EINVAL;
1556 1555
1557 skb_chk = skb_checksum_trimmed(skb, transport_len,1556 skb_chk = skb_checksum_trimmed(skb, transport_len,
1558 ip_mc_validate_checksum);1557 ip_mc_validate_checksum);
1559 if (!skb_chk)1558 if (!skb_chk)
1560 goto err;1559 return -EINVAL;
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;
1570 1560
1571err:1561 if (skb_chk != skb)
1572 if (skb_chk && skb_chk != skb)
1573 kfree_skb(skb_chk);1562 kfree_skb(skb_chk);
1574 1563
1575 return ret;1564 return 0;
1576}1565}
1577 1566
1578/**1567/**
@@ -1600,7 +1589,11 @@ int ip_mc_check_igmp(struct sk_buff *skb) · 21 unmodified lines
1600 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)1589 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
1601 return -ENOMSG;1590 return -ENOMSG;
1602 1591
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);
1604}1597}
1605EXPORT_SYMBOL(ip_mc_check_igmp);1598EXPORT_SYMBOL(ip_mc_check_igmp);
1606 1599
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
77 77
78 len += sizeof(struct mld2_report);78 len += sizeof(struct mld2_report);
79 79
80 return pskb_may_pull(skb, len) ? 0 : -EINVAL;80 return ipv6_mc_may_pull(skb, len) ? 0 : -EINVAL;
81}81}
82 82
83static int ipv6_mc_check_mld_query(struct sk_buff *skb)83static int ipv6_mc_check_mld_query(struct sk_buff *skb)
84{84{
85 unsigned int transport_len = ipv6_transport_len(skb);
85 struct mld_msg *mld;86 struct mld_msg *mld;
86 unsigned int len = skb_transport_offset(skb);87 unsigned int len;
87 88
88 /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */89 /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
89 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))90 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
90 return -EINVAL;91 return -EINVAL;
91 92
92 len += sizeof(struct mld_msg);
93 if (skb->len < len)
94 return -EINVAL;
95
96 /* MLDv1? */93 /* MLDv1? */
97 if (skb->len != len) {94 if (transport_len != sizeof(struct mld_msg)) {
98 /* or MLDv2? */95 /* or MLDv2? */
99 len += sizeof(struct mld2_query) - sizeof(struct mld_msg);96 if (transport_len < sizeof(struct mld2_query))
100 if (skb->len < len || !pskb_may_pull(skb, len))97 return -EINVAL;
98
99 len = skb_transport_offset(skb) + sizeof(struct mld2_query);
100 if (!ipv6_mc_may_pull(skb, len))
101 return -EINVAL;101 return -EINVAL;
102 }102 }
103 103
@@ -115,7 +115,13 @@ static int ipv6_mc_check_mld_query(struct sk_buff *skb) · 11 unmodified lines
115 115
116static int ipv6_mc_check_mld_msg(struct sk_buff *skb)116static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
117{117{
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);
119 125
120 switch (mld->mld_type) {126 switch (mld->mld_type) {
121 case ICMPV6_MGM_REDUCTION:127 case ICMPV6_MGM_REDUCTION:
@@ -136,36 +142,24 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb) · 14 unmodified lines
136 return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);142 return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
137}143}
138 144
139static int __ipv6_mc_check_mld(struct sk_buff *skb)145static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
140
141{146{
142 struct sk_buff *skb_chk = NULL;147 unsigned int len = skb_transport_offset(skb) + sizeof(struct icmp6hdr);
143 unsigned int transport_len;148 unsigned int transport_len = ipv6_transport_len(skb);
144 unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);149 struct sk_buff *skb_chk;
145 int ret = -EINVAL;
146 150
147 transport_len = ntohs(ipv6_hdr(skb)->payload_len);151 if (!ipv6_mc_may_pull(skb, len))
148 transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);152 return -EINVAL;
149 153
150 skb_chk = skb_checksum_trimmed(skb, transport_len,154 skb_chk = skb_checksum_trimmed(skb, transport_len,
151 ipv6_mc_validate_checksum);155 ipv6_mc_validate_checksum);
152 if (!skb_chk)156 if (!skb_chk)
153 goto err;157 return -EINVAL;
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;
163 158
164err:159 if (skb_chk != skb)
165 if (skb_chk && skb_chk != skb)
166 kfree_skb(skb_chk);160 kfree_skb(skb_chk);
167 161
168 return ret;162 return 0;
169}163}
170 164
171/**165/**
@@ -195,6 +189,10 @@ int ipv6_mc_check_mld(struct sk_buff *skb) · 23 unmodified lines
195 if (ret < 0)189 if (ret < 0)
196 return ret;190 return ret;
197 191
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);
199}197}
200EXPORT_SYMBOL(ipv6_mc_check_mld);198EXPORT_SYMBOL(ipv6_mc_check_mld);