| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | *	Linux NET3:	Internet Group Management Protocol  [IGMP] | 
|---|
| 3 | 4 | * | 
|---|
| .. | .. | 
|---|
| 10 | 11 | * | 
|---|
| 11 | 12 | *	Authors: | 
|---|
| 12 | 13 | *		Alan Cox <alan@lxorguk.ukuu.org.uk> | 
|---|
| 13 |  | - * | 
|---|
| 14 |  | - *	This program is free software; you can redistribute it and/or | 
|---|
| 15 |  | - *	modify it under the terms of the GNU General Public License | 
|---|
| 16 |  | - *	as published by the Free Software Foundation; either version | 
|---|
| 17 |  | - *	2 of the License, or (at your option) any later version. | 
|---|
| 18 | 14 | * | 
|---|
| 19 | 15 | *	Fixes: | 
|---|
| 20 | 16 | * | 
|---|
| .. | .. | 
|---|
| 111 | 107 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 112 | 108 | /* Parameter names and values are taken from igmp-v2-06 draft */ | 
|---|
| 113 | 109 |  | 
|---|
| 114 |  | -#define IGMP_V2_UNSOLICITED_REPORT_INTERVAL	(10*HZ) | 
|---|
| 115 |  | -#define IGMP_V3_UNSOLICITED_REPORT_INTERVAL	(1*HZ) | 
|---|
| 116 | 110 | #define IGMP_QUERY_INTERVAL			(125*HZ) | 
|---|
| 117 | 111 | #define IGMP_QUERY_RESPONSE_INTERVAL		(10*HZ) | 
|---|
| 118 | 112 |  | 
|---|
| .. | .. | 
|---|
| 159 | 153 | return interval_jiffies; | 
|---|
| 160 | 154 | } | 
|---|
| 161 | 155 |  | 
|---|
| 162 |  | -static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im); | 
|---|
|  | 156 | +static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im, | 
|---|
|  | 157 | +			      gfp_t gfp); | 
|---|
| 163 | 158 | static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im); | 
|---|
| 164 | 159 | static void igmpv3_clear_delrec(struct in_device *in_dev); | 
|---|
| 165 | 160 | static int sf_setstate(struct ip_mc_list *pmc); | 
|---|
| .. | .. | 
|---|
| 335 | 330 | const struct flowi4 *fl4) | 
|---|
| 336 | 331 | { | 
|---|
| 337 | 332 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 
|---|
|  | 333 | +	const struct in_ifaddr *ifa; | 
|---|
| 338 | 334 |  | 
|---|
| 339 | 335 | if (!in_dev) | 
|---|
| 340 | 336 | return htonl(INADDR_ANY); | 
|---|
| 341 | 337 |  | 
|---|
| 342 |  | -	for_ifa(in_dev) { | 
|---|
|  | 338 | +	in_dev_for_each_ifa_rcu(ifa, in_dev) { | 
|---|
| 343 | 339 | if (fl4->saddr == ifa->ifa_local) | 
|---|
| 344 | 340 | return fl4->saddr; | 
|---|
| 345 |  | -	} endfor_ifa(in_dev); | 
|---|
|  | 341 | +	} | 
|---|
| 346 | 342 |  | 
|---|
| 347 | 343 | return htonl(INADDR_ANY); | 
|---|
| 348 | 344 | } | 
|---|
| .. | .. | 
|---|
| 357 | 353 | struct flowi4 fl4; | 
|---|
| 358 | 354 | int hlen = LL_RESERVED_SPACE(dev); | 
|---|
| 359 | 355 | int tlen = dev->needed_tailroom; | 
|---|
| 360 |  | -	unsigned int size = mtu; | 
|---|
|  | 356 | +	unsigned int size; | 
|---|
| 361 | 357 |  | 
|---|
|  | 358 | +	size = min(mtu, IP_MAX_MTU); | 
|---|
| 362 | 359 | while (1) { | 
|---|
| 363 | 360 | skb = alloc_skb(size + hlen + tlen, | 
|---|
| 364 | 361 | GFP_ATOMIC | __GFP_NOWARN); | 
|---|
| .. | .. | 
|---|
| 471 | 468 |  | 
|---|
| 472 | 469 | if (pmc->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 473 | 470 | return skb; | 
|---|
| 474 |  | -	if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 471 | +	if (ipv4_is_local_multicast(pmc->multiaddr) && | 
|---|
|  | 472 | +	    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 475 | 473 | return skb; | 
|---|
| 476 | 474 |  | 
|---|
| 477 | 475 | mtu = READ_ONCE(dev->mtu); | 
|---|
| .. | .. | 
|---|
| 597 | 595 | if (pmc->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 598 | 596 | continue; | 
|---|
| 599 | 597 | if (ipv4_is_local_multicast(pmc->multiaddr) && | 
|---|
| 600 |  | -			     !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 598 | +			    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 601 | 599 | continue; | 
|---|
| 602 | 600 | spin_lock_bh(&pmc->lock); | 
|---|
| 603 | 601 | if (pmc->sfcount[MCAST_EXCLUDE]) | 
|---|
| .. | .. | 
|---|
| 740 | 738 | if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) | 
|---|
| 741 | 739 | return igmpv3_send_report(in_dev, pmc); | 
|---|
| 742 | 740 |  | 
|---|
| 743 |  | -	if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 741 | +	if (ipv4_is_local_multicast(group) && | 
|---|
|  | 742 | +	    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 744 | 743 | return 0; | 
|---|
| 745 | 744 |  | 
|---|
| 746 | 745 | if (type == IGMP_HOST_LEAVE_MESSAGE) | 
|---|
| .. | .. | 
|---|
| 822 | 821 | struct net *net = dev_net(in_dev->dev); | 
|---|
| 823 | 822 | if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) | 
|---|
| 824 | 823 | return; | 
|---|
| 825 |  | -	in_dev->mr_ifc_count = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 824 | +	in_dev->mr_ifc_count = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 826 | 825 | igmp_ifc_start_timer(in_dev, 1); | 
|---|
| 827 | 826 | } | 
|---|
| 828 | 827 |  | 
|---|
| .. | .. | 
|---|
| 917 | 916 |  | 
|---|
| 918 | 917 | if (group == IGMP_ALL_HOSTS) | 
|---|
| 919 | 918 | return false; | 
|---|
| 920 |  | -	if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 919 | +	if (ipv4_is_local_multicast(group) && | 
|---|
|  | 920 | +	    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 921 | 921 | return false; | 
|---|
| 922 | 922 |  | 
|---|
| 923 | 923 | rcu_read_lock(); | 
|---|
| .. | .. | 
|---|
| 1003 | 1003 | * received value was zero, use the default or statically | 
|---|
| 1004 | 1004 | * configured value. | 
|---|
| 1005 | 1005 | */ | 
|---|
| 1006 |  | -		in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1006 | +		in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1007 | 1007 | in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL; | 
|---|
| 1008 | 1008 |  | 
|---|
| 1009 | 1009 | /* RFC3376, 8.3. Query Response Interval: | 
|---|
| .. | .. | 
|---|
| 1042 | 1042 | if (im->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 1043 | 1043 | continue; | 
|---|
| 1044 | 1044 | if (ipv4_is_local_multicast(im->multiaddr) && | 
|---|
| 1045 |  | -		    !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 1045 | +		    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 1046 | 1046 | continue; | 
|---|
| 1047 | 1047 | spin_lock_bh(&im->lock); | 
|---|
| 1048 | 1048 | if (im->tm_running) | 
|---|
| .. | .. | 
|---|
| 1163 | 1163 | /* | 
|---|
| 1164 | 1164 | * deleted ip_mc_list manipulation | 
|---|
| 1165 | 1165 | */ | 
|---|
| 1166 |  | -static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) | 
|---|
|  | 1166 | +static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im, | 
|---|
|  | 1167 | +			      gfp_t gfp) | 
|---|
| 1167 | 1168 | { | 
|---|
| 1168 | 1169 | struct ip_mc_list *pmc; | 
|---|
| 1169 | 1170 | struct net *net = dev_net(in_dev->dev); | 
|---|
| .. | .. | 
|---|
| 1174 | 1175 | * for deleted items allows change reports to use common code with | 
|---|
| 1175 | 1176 | * non-deleted or query-response MCA's. | 
|---|
| 1176 | 1177 | */ | 
|---|
| 1177 |  | -	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); | 
|---|
|  | 1178 | +	pmc = kzalloc(sizeof(*pmc), gfp); | 
|---|
| 1178 | 1179 | if (!pmc) | 
|---|
| 1179 | 1180 | return; | 
|---|
| 1180 | 1181 | spin_lock_init(&pmc->lock); | 
|---|
| .. | .. | 
|---|
| 1182 | 1183 | pmc->interface = im->interface; | 
|---|
| 1183 | 1184 | in_dev_hold(in_dev); | 
|---|
| 1184 | 1185 | pmc->multiaddr = im->multiaddr; | 
|---|
| 1185 |  | -	pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1186 | +	pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1186 | 1187 | pmc->sfmode = im->sfmode; | 
|---|
| 1187 | 1188 | if (pmc->sfmode == MCAST_INCLUDE) { | 
|---|
| 1188 | 1189 | struct ip_sf_list *psf; | 
|---|
| .. | .. | 
|---|
| 1233 | 1234 | swap(im->tomb, pmc->tomb); | 
|---|
| 1234 | 1235 | swap(im->sources, pmc->sources); | 
|---|
| 1235 | 1236 | for (psf = im->sources; psf; psf = psf->sf_next) | 
|---|
| 1236 |  | -				psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1237 | +				psf->sf_crcount = in_dev->mr_qrv ?: | 
|---|
|  | 1238 | +					READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1237 | 1239 | } else { | 
|---|
| 1238 |  | -			im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1240 | +			im->crcount = in_dev->mr_qrv ?: | 
|---|
|  | 1241 | +				READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1239 | 1242 | } | 
|---|
| 1240 | 1243 | in_dev_put(pmc->interface); | 
|---|
| 1241 | 1244 | kfree_pmc(pmc); | 
|---|
| .. | .. | 
|---|
| 1276 | 1279 | } | 
|---|
| 1277 | 1280 | #endif | 
|---|
| 1278 | 1281 |  | 
|---|
| 1279 |  | -static void igmp_group_dropped(struct ip_mc_list *im) | 
|---|
|  | 1282 | +static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp) | 
|---|
| 1280 | 1283 | { | 
|---|
| 1281 | 1284 | struct in_device *in_dev = im->interface; | 
|---|
| 1282 | 1285 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| .. | .. | 
|---|
| 1292 | 1295 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 1293 | 1296 | if (im->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 1294 | 1297 | return; | 
|---|
| 1295 |  | -	if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 1298 | +	if (ipv4_is_local_multicast(im->multiaddr) && | 
|---|
|  | 1299 | +	    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 1296 | 1300 | return; | 
|---|
| 1297 | 1301 |  | 
|---|
| 1298 | 1302 | reporter = im->reporter; | 
|---|
| .. | .. | 
|---|
| 1307 | 1311 | return; | 
|---|
| 1308 | 1312 | } | 
|---|
| 1309 | 1313 | /* IGMPv3 */ | 
|---|
| 1310 |  | -		igmpv3_add_delrec(in_dev, im); | 
|---|
|  | 1314 | +		igmpv3_add_delrec(in_dev, im, gfp); | 
|---|
| 1311 | 1315 |  | 
|---|
| 1312 | 1316 | igmp_ifc_event(in_dev); | 
|---|
| 1313 | 1317 | } | 
|---|
| 1314 | 1318 | #endif | 
|---|
|  | 1319 | +} | 
|---|
|  | 1320 | + | 
|---|
|  | 1321 | +static void igmp_group_dropped(struct ip_mc_list *im) | 
|---|
|  | 1322 | +{ | 
|---|
|  | 1323 | +	__igmp_group_dropped(im, GFP_KERNEL); | 
|---|
| 1315 | 1324 | } | 
|---|
| 1316 | 1325 |  | 
|---|
| 1317 | 1326 | static void igmp_group_added(struct ip_mc_list *im) | 
|---|
| .. | .. | 
|---|
| 1329 | 1338 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 1330 | 1339 | if (im->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 1331 | 1340 | return; | 
|---|
| 1332 |  | -	if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 1341 | +	if (ipv4_is_local_multicast(im->multiaddr) && | 
|---|
|  | 1342 | +	    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 1333 | 1343 | return; | 
|---|
| 1334 | 1344 |  | 
|---|
| 1335 | 1345 | if (in_dev->dead) | 
|---|
| 1336 | 1346 | return; | 
|---|
| 1337 | 1347 |  | 
|---|
| 1338 |  | -	im->unsolicit_count = net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1348 | +	im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1339 | 1349 | if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) { | 
|---|
| 1340 | 1350 | spin_lock_bh(&im->lock); | 
|---|
| 1341 | 1351 | igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY); | 
|---|
| .. | .. | 
|---|
| 1349 | 1359 | * IN() to IN(A). | 
|---|
| 1350 | 1360 | */ | 
|---|
| 1351 | 1361 | if (im->sfmode == MCAST_EXCLUDE) | 
|---|
| 1352 |  | -		im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1362 | +		im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1353 | 1363 |  | 
|---|
| 1354 | 1364 | igmp_ifc_event(in_dev); | 
|---|
| 1355 | 1365 | #endif | 
|---|
| .. | .. | 
|---|
| 1415 | 1425 | /* | 
|---|
| 1416 | 1426 | *	A socket has joined a multicast group on device dev. | 
|---|
| 1417 | 1427 | */ | 
|---|
| 1418 |  | -static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, | 
|---|
| 1419 |  | -			      unsigned int mode) | 
|---|
|  | 1428 | +static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr, | 
|---|
|  | 1429 | +				unsigned int mode, gfp_t gfp) | 
|---|
| 1420 | 1430 | { | 
|---|
| 1421 | 1431 | struct ip_mc_list *im; | 
|---|
| 1422 | 1432 |  | 
|---|
| .. | .. | 
|---|
| 1430 | 1440 | } | 
|---|
| 1431 | 1441 | } | 
|---|
| 1432 | 1442 |  | 
|---|
| 1433 |  | -	im = kzalloc(sizeof(*im), GFP_KERNEL); | 
|---|
|  | 1443 | +	im = kzalloc(sizeof(*im), gfp); | 
|---|
| 1434 | 1444 | if (!im) | 
|---|
| 1435 | 1445 | goto out; | 
|---|
| 1436 | 1446 |  | 
|---|
| .. | .. | 
|---|
| 1463 | 1473 | return; | 
|---|
| 1464 | 1474 | } | 
|---|
| 1465 | 1475 |  | 
|---|
|  | 1476 | +void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, gfp_t gfp) | 
|---|
|  | 1477 | +{ | 
|---|
|  | 1478 | +	____ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE, gfp); | 
|---|
|  | 1479 | +} | 
|---|
|  | 1480 | +EXPORT_SYMBOL(__ip_mc_inc_group); | 
|---|
|  | 1481 | + | 
|---|
| 1466 | 1482 | void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | 
|---|
| 1467 | 1483 | { | 
|---|
| 1468 |  | -	__ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE); | 
|---|
|  | 1484 | +	__ip_mc_inc_group(in_dev, addr, GFP_KERNEL); | 
|---|
| 1469 | 1485 | } | 
|---|
| 1470 | 1486 | EXPORT_SYMBOL(ip_mc_inc_group); | 
|---|
| 1471 | 1487 |  | 
|---|
| .. | .. | 
|---|
| 1508 | 1524 |  | 
|---|
| 1509 | 1525 | len += sizeof(struct igmpv3_report); | 
|---|
| 1510 | 1526 |  | 
|---|
| 1511 |  | -	return pskb_may_pull(skb, len) ? 0 : -EINVAL; | 
|---|
|  | 1527 | +	return ip_mc_may_pull(skb, len) ? 0 : -EINVAL; | 
|---|
| 1512 | 1528 | } | 
|---|
| 1513 | 1529 |  | 
|---|
| 1514 | 1530 | static int ip_mc_check_igmp_query(struct sk_buff *skb) | 
|---|
| 1515 | 1531 | { | 
|---|
| 1516 |  | -	unsigned int len = skb_transport_offset(skb); | 
|---|
| 1517 |  | - | 
|---|
| 1518 |  | -	len += sizeof(struct igmphdr); | 
|---|
| 1519 |  | -	if (skb->len < len) | 
|---|
| 1520 |  | -		return -EINVAL; | 
|---|
|  | 1532 | +	unsigned int transport_len = ip_transport_len(skb); | 
|---|
|  | 1533 | +	unsigned int len; | 
|---|
| 1521 | 1534 |  | 
|---|
| 1522 | 1535 | /* IGMPv{1,2}? */ | 
|---|
| 1523 |  | -	if (skb->len != len) { | 
|---|
|  | 1536 | +	if (transport_len != sizeof(struct igmphdr)) { | 
|---|
| 1524 | 1537 | /* or IGMPv3? */ | 
|---|
| 1525 |  | -		len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr); | 
|---|
| 1526 |  | -		if (skb->len < len || !pskb_may_pull(skb, len)) | 
|---|
|  | 1538 | +		if (transport_len < sizeof(struct igmpv3_query)) | 
|---|
|  | 1539 | +			return -EINVAL; | 
|---|
|  | 1540 | + | 
|---|
|  | 1541 | +		len = skb_transport_offset(skb) + sizeof(struct igmpv3_query); | 
|---|
|  | 1542 | +		if (!ip_mc_may_pull(skb, len)) | 
|---|
| 1527 | 1543 | return -EINVAL; | 
|---|
| 1528 | 1544 | } | 
|---|
| 1529 | 1545 |  | 
|---|
| .. | .. | 
|---|
| 1543 | 1559 | case IGMP_HOST_LEAVE_MESSAGE: | 
|---|
| 1544 | 1560 | case IGMP_HOST_MEMBERSHIP_REPORT: | 
|---|
| 1545 | 1561 | case IGMPV2_HOST_MEMBERSHIP_REPORT: | 
|---|
| 1546 |  | -		/* fall through */ | 
|---|
| 1547 | 1562 | return 0; | 
|---|
| 1548 | 1563 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | 
|---|
| 1549 | 1564 | return ip_mc_check_igmp_reportv3(skb); | 
|---|
| .. | .. | 
|---|
| 1554 | 1569 | } | 
|---|
| 1555 | 1570 | } | 
|---|
| 1556 | 1571 |  | 
|---|
| 1557 |  | -static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) | 
|---|
|  | 1572 | +static __sum16 ip_mc_validate_checksum(struct sk_buff *skb) | 
|---|
| 1558 | 1573 | { | 
|---|
| 1559 | 1574 | return skb_checksum_simple_validate(skb); | 
|---|
| 1560 | 1575 | } | 
|---|
| 1561 | 1576 |  | 
|---|
| 1562 |  | -static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) | 
|---|
| 1563 |  | - | 
|---|
|  | 1577 | +static int ip_mc_check_igmp_csum(struct sk_buff *skb) | 
|---|
| 1564 | 1578 | { | 
|---|
| 1565 |  | -	struct sk_buff *skb_chk; | 
|---|
| 1566 |  | -	unsigned int transport_len; | 
|---|
| 1567 | 1579 | unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr); | 
|---|
| 1568 |  | -	int ret = -EINVAL; | 
|---|
|  | 1580 | +	unsigned int transport_len = ip_transport_len(skb); | 
|---|
|  | 1581 | +	struct sk_buff *skb_chk; | 
|---|
| 1569 | 1582 |  | 
|---|
| 1570 |  | -	transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb); | 
|---|
|  | 1583 | +	if (!ip_mc_may_pull(skb, len)) | 
|---|
|  | 1584 | +		return -EINVAL; | 
|---|
| 1571 | 1585 |  | 
|---|
| 1572 | 1586 | skb_chk = skb_checksum_trimmed(skb, transport_len, | 
|---|
| 1573 | 1587 | ip_mc_validate_checksum); | 
|---|
| 1574 | 1588 | if (!skb_chk) | 
|---|
| 1575 |  | -		goto err; | 
|---|
|  | 1589 | +		return -EINVAL; | 
|---|
| 1576 | 1590 |  | 
|---|
| 1577 |  | -	if (!pskb_may_pull(skb_chk, len)) | 
|---|
| 1578 |  | -		goto err; | 
|---|
| 1579 |  | - | 
|---|
| 1580 |  | -	ret = ip_mc_check_igmp_msg(skb_chk); | 
|---|
| 1581 |  | -	if (ret) | 
|---|
| 1582 |  | -		goto err; | 
|---|
| 1583 |  | - | 
|---|
| 1584 |  | -	if (skb_trimmed) | 
|---|
| 1585 |  | -		*skb_trimmed = skb_chk; | 
|---|
| 1586 |  | -	/* free now unneeded clone */ | 
|---|
| 1587 |  | -	else if (skb_chk != skb) | 
|---|
|  | 1591 | +	if (skb_chk != skb) | 
|---|
| 1588 | 1592 | kfree_skb(skb_chk); | 
|---|
| 1589 | 1593 |  | 
|---|
| 1590 |  | -	ret = 0; | 
|---|
| 1591 |  | - | 
|---|
| 1592 |  | -err: | 
|---|
| 1593 |  | -	if (ret && skb_chk && skb_chk != skb) | 
|---|
| 1594 |  | -		kfree_skb(skb_chk); | 
|---|
| 1595 |  | - | 
|---|
| 1596 |  | -	return ret; | 
|---|
|  | 1594 | +	return 0; | 
|---|
| 1597 | 1595 | } | 
|---|
| 1598 | 1596 |  | 
|---|
| 1599 | 1597 | /** | 
|---|
| 1600 | 1598 | * ip_mc_check_igmp - checks whether this is a sane IGMP packet | 
|---|
| 1601 | 1599 | * @skb: the skb to validate | 
|---|
| 1602 |  | - * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional) | 
|---|
| 1603 | 1600 | * | 
|---|
| 1604 | 1601 | * Checks whether an IPv4 packet is a valid IGMP packet. If so sets | 
|---|
| 1605 | 1602 | * skb transport header accordingly and returns zero. | 
|---|
| .. | .. | 
|---|
| 1609 | 1606 | * -ENOMSG: IP header validation succeeded but it is not an IGMP packet. | 
|---|
| 1610 | 1607 | * -ENOMEM: A memory allocation failure happened. | 
|---|
| 1611 | 1608 | * | 
|---|
| 1612 |  | - * Optionally, an skb pointer might be provided via skb_trimmed (or set it | 
|---|
| 1613 |  | - * to NULL): After parsing an IGMP packet successfully it will point to | 
|---|
| 1614 |  | - * an skb which has its tail aligned to the IP packet end. This might | 
|---|
| 1615 |  | - * either be the originally provided skb or a trimmed, cloned version if | 
|---|
| 1616 |  | - * the skb frame had data beyond the IP packet. A cloned skb allows us | 
|---|
| 1617 |  | - * to leave the original skb and its full frame unchanged (which might be | 
|---|
| 1618 |  | - * desirable for layer 2 frame jugglers). | 
|---|
| 1619 |  | - * | 
|---|
| 1620 | 1609 | * Caller needs to set the skb network header and free any returned skb if it | 
|---|
| 1621 | 1610 | * differs from the provided skb. | 
|---|
| 1622 | 1611 | */ | 
|---|
| 1623 |  | -int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) | 
|---|
|  | 1612 | +int ip_mc_check_igmp(struct sk_buff *skb) | 
|---|
| 1624 | 1613 | { | 
|---|
| 1625 | 1614 | int ret = ip_mc_check_iphdr(skb); | 
|---|
| 1626 | 1615 |  | 
|---|
| .. | .. | 
|---|
| 1630 | 1619 | if (ip_hdr(skb)->protocol != IPPROTO_IGMP) | 
|---|
| 1631 | 1620 | return -ENOMSG; | 
|---|
| 1632 | 1621 |  | 
|---|
| 1633 |  | -	return __ip_mc_check_igmp(skb, skb_trimmed); | 
|---|
|  | 1622 | +	ret = ip_mc_check_igmp_csum(skb); | 
|---|
|  | 1623 | +	if (ret < 0) | 
|---|
|  | 1624 | +		return ret; | 
|---|
|  | 1625 | + | 
|---|
|  | 1626 | +	return ip_mc_check_igmp_msg(skb); | 
|---|
| 1634 | 1627 | } | 
|---|
| 1635 | 1628 | EXPORT_SYMBOL(ip_mc_check_igmp); | 
|---|
| 1636 | 1629 |  | 
|---|
| .. | .. | 
|---|
| 1650 | 1643 | if (im->multiaddr == IGMP_ALL_HOSTS) | 
|---|
| 1651 | 1644 | continue; | 
|---|
| 1652 | 1645 | if (ipv4_is_local_multicast(im->multiaddr) && | 
|---|
| 1653 |  | -		    !net->ipv4.sysctl_igmp_llm_reports) | 
|---|
|  | 1646 | +		    !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports)) | 
|---|
| 1654 | 1647 | continue; | 
|---|
| 1655 | 1648 |  | 
|---|
| 1656 | 1649 | /* a failover is happening and switches | 
|---|
| .. | .. | 
|---|
| 1671 | 1664 | *	A socket has left a multicast group on device dev | 
|---|
| 1672 | 1665 | */ | 
|---|
| 1673 | 1666 |  | 
|---|
| 1674 |  | -void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) | 
|---|
|  | 1667 | +void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp) | 
|---|
| 1675 | 1668 | { | 
|---|
| 1676 | 1669 | struct ip_mc_list *i; | 
|---|
| 1677 | 1670 | struct ip_mc_list __rcu **ip; | 
|---|
| .. | .. | 
|---|
| 1686 | 1679 | ip_mc_hash_remove(in_dev, i); | 
|---|
| 1687 | 1680 | *ip = i->next_rcu; | 
|---|
| 1688 | 1681 | in_dev->mc_count--; | 
|---|
| 1689 |  | -				igmp_group_dropped(i); | 
|---|
|  | 1682 | +				__igmp_group_dropped(i, gfp); | 
|---|
| 1690 | 1683 | ip_mc_clear_src(i); | 
|---|
| 1691 | 1684 |  | 
|---|
| 1692 | 1685 | if (!in_dev->dead) | 
|---|
| .. | .. | 
|---|
| 1699 | 1692 | } | 
|---|
| 1700 | 1693 | } | 
|---|
| 1701 | 1694 | } | 
|---|
| 1702 |  | -EXPORT_SYMBOL(ip_mc_dec_group); | 
|---|
|  | 1695 | +EXPORT_SYMBOL(__ip_mc_dec_group); | 
|---|
| 1703 | 1696 |  | 
|---|
| 1704 | 1697 | /* Device changing type */ | 
|---|
| 1705 | 1698 |  | 
|---|
| .. | .. | 
|---|
| 1757 | 1750 |  | 
|---|
| 1758 | 1751 | in_dev->mr_qi = IGMP_QUERY_INTERVAL; | 
|---|
| 1759 | 1752 | in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL; | 
|---|
| 1760 |  | -	in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1753 | +	in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1761 | 1754 | } | 
|---|
| 1762 | 1755 | #else | 
|---|
| 1763 | 1756 | static void ip_mc_reset(struct in_device *in_dev) | 
|---|
| .. | .. | 
|---|
| 1891 | 1884 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 1892 | 1885 | if (psf->sf_oldin && | 
|---|
| 1893 | 1886 | !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) { | 
|---|
| 1894 |  | -			psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1887 | +			psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1895 | 1888 | psf->sf_next = pmc->tomb; | 
|---|
| 1896 | 1889 | pmc->tomb = psf; | 
|---|
| 1897 | 1890 | rv = 1; | 
|---|
| .. | .. | 
|---|
| 1955 | 1948 | /* filter mode change */ | 
|---|
| 1956 | 1949 | pmc->sfmode = MCAST_INCLUDE; | 
|---|
| 1957 | 1950 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 1958 |  | -		pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 1951 | +		pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 1959 | 1952 | in_dev->mr_ifc_count = pmc->crcount; | 
|---|
| 1960 | 1953 | for (psf = pmc->sources; psf; psf = psf->sf_next) | 
|---|
| 1961 | 1954 | psf->sf_crcount = 0; | 
|---|
| .. | .. | 
|---|
| 2134 | 2127 | #ifdef CONFIG_IP_MULTICAST | 
|---|
| 2135 | 2128 | /* else no filters; keep old mode for reports */ | 
|---|
| 2136 | 2129 |  | 
|---|
| 2137 |  | -		pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; | 
|---|
|  | 2130 | +		pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); | 
|---|
| 2138 | 2131 | in_dev->mr_ifc_count = pmc->crcount; | 
|---|
| 2139 | 2132 | for (psf = pmc->sources; psf; psf = psf->sf_next) | 
|---|
| 2140 | 2133 | psf->sf_crcount = 0; | 
|---|
| .. | .. | 
|---|
| 2200 | 2193 | count++; | 
|---|
| 2201 | 2194 | } | 
|---|
| 2202 | 2195 | err = -ENOBUFS; | 
|---|
| 2203 |  | -	if (count >= net->ipv4.sysctl_igmp_max_memberships) | 
|---|
|  | 2196 | +	if (count >= READ_ONCE(net->ipv4.sysctl_igmp_max_memberships)) | 
|---|
| 2204 | 2197 | goto done; | 
|---|
| 2205 | 2198 | iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); | 
|---|
| 2206 | 2199 | if (!iml) | 
|---|
| .. | .. | 
|---|
| 2211 | 2204 | iml->sflist = NULL; | 
|---|
| 2212 | 2205 | iml->sfmode = mode; | 
|---|
| 2213 | 2206 | rcu_assign_pointer(inet->mc_list, iml); | 
|---|
| 2214 |  | -	__ip_mc_inc_group(in_dev, addr, mode); | 
|---|
|  | 2207 | +	____ip_mc_inc_group(in_dev, addr, mode, GFP_KERNEL); | 
|---|
| 2215 | 2208 | err = 0; | 
|---|
| 2216 | 2209 | done: | 
|---|
| 2217 | 2210 | return err; | 
|---|
| .. | .. | 
|---|
| 2387 | 2380 | } | 
|---|
| 2388 | 2381 | /* else, add a new source to the filter */ | 
|---|
| 2389 | 2382 |  | 
|---|
| 2390 |  | -	if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) { | 
|---|
|  | 2383 | +	if (psl && psl->sl_count >= READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) { | 
|---|
| 2391 | 2384 | err = -ENOBUFS; | 
|---|
| 2392 | 2385 | goto done; | 
|---|
| 2393 | 2386 | } | 
|---|
| .. | .. | 
|---|
| 2409 | 2402 | newpsl->sl_addr[i] = psl->sl_addr[i]; | 
|---|
| 2410 | 2403 | /* decrease mem now to avoid the memleak warning */ | 
|---|
| 2411 | 2404 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); | 
|---|
| 2412 |  | -			kfree_rcu(psl, rcu); | 
|---|
| 2413 | 2405 | } | 
|---|
| 2414 | 2406 | rcu_assign_pointer(pmc->sflist, newpsl); | 
|---|
|  | 2407 | +		if (psl) | 
|---|
|  | 2408 | +			kfree_rcu(psl, rcu); | 
|---|
| 2415 | 2409 | psl = newpsl; | 
|---|
| 2416 | 2410 | } | 
|---|
| 2417 | 2411 | rv = 1;	/* > 0 for insert logic below if sl_count is 0 */ | 
|---|
| .. | .. | 
|---|
| 2509 | 2503 | psl->sl_count, psl->sl_addr, 0); | 
|---|
| 2510 | 2504 | /* decrease mem now to avoid the memleak warning */ | 
|---|
| 2511 | 2505 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); | 
|---|
| 2512 |  | -		kfree_rcu(psl, rcu); | 
|---|
| 2513 |  | -	} else | 
|---|
|  | 2506 | +	} else { | 
|---|
| 2514 | 2507 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, | 
|---|
| 2515 | 2508 | 0, NULL, 0); | 
|---|
|  | 2509 | +	} | 
|---|
| 2516 | 2510 | rcu_assign_pointer(pmc->sflist, newpsl); | 
|---|
|  | 2511 | +	if (psl) | 
|---|
|  | 2512 | +		kfree_rcu(psl, rcu); | 
|---|
| 2517 | 2513 | pmc->sfmode = msf->imsf_fmode; | 
|---|
| 2518 | 2514 | err = 0; | 
|---|
| 2519 | 2515 | done: | 
|---|
| .. | .. | 
|---|
| 2581 | 2577 | } | 
|---|
| 2582 | 2578 |  | 
|---|
| 2583 | 2579 | int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | 
|---|
| 2584 |  | -	struct group_filter __user *optval, int __user *optlen) | 
|---|
|  | 2580 | +	struct sockaddr_storage __user *p) | 
|---|
| 2585 | 2581 | { | 
|---|
| 2586 |  | -	int err, i, count, copycount; | 
|---|
|  | 2582 | +	int i, count, copycount; | 
|---|
| 2587 | 2583 | struct sockaddr_in *psin; | 
|---|
| 2588 | 2584 | __be32 addr; | 
|---|
| 2589 | 2585 | struct ip_mc_socklist *pmc; | 
|---|
| .. | .. | 
|---|
| 2599 | 2595 | if (!ipv4_is_multicast(addr)) | 
|---|
| 2600 | 2596 | return -EINVAL; | 
|---|
| 2601 | 2597 |  | 
|---|
| 2602 |  | -	err = -EADDRNOTAVAIL; | 
|---|
| 2603 |  | - | 
|---|
| 2604 | 2598 | for_each_pmc_rtnl(inet, pmc) { | 
|---|
| 2605 | 2599 | if (pmc->multi.imr_multiaddr.s_addr == addr && | 
|---|
| 2606 | 2600 | pmc->multi.imr_ifindex == gsf->gf_interface) | 
|---|
| 2607 | 2601 | break; | 
|---|
| 2608 | 2602 | } | 
|---|
| 2609 | 2603 | if (!pmc)		/* must have a prior join */ | 
|---|
| 2610 |  | -		goto done; | 
|---|
|  | 2604 | +		return -EADDRNOTAVAIL; | 
|---|
| 2611 | 2605 | gsf->gf_fmode = pmc->sfmode; | 
|---|
| 2612 | 2606 | psl = rtnl_dereference(pmc->sflist); | 
|---|
| 2613 | 2607 | count = psl ? psl->sl_count : 0; | 
|---|
| 2614 | 2608 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; | 
|---|
| 2615 | 2609 | gsf->gf_numsrc = count; | 
|---|
| 2616 |  | -	if (put_user(GROUP_FILTER_SIZE(copycount), optlen) || | 
|---|
| 2617 |  | -	    copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { | 
|---|
| 2618 |  | -		return -EFAULT; | 
|---|
| 2619 |  | -	} | 
|---|
| 2620 |  | -	for (i = 0; i < copycount; i++) { | 
|---|
|  | 2610 | +	for (i = 0; i < copycount; i++, p++) { | 
|---|
| 2621 | 2611 | struct sockaddr_storage ss; | 
|---|
| 2622 | 2612 |  | 
|---|
| 2623 | 2613 | psin = (struct sockaddr_in *)&ss; | 
|---|
| 2624 | 2614 | memset(&ss, 0, sizeof(ss)); | 
|---|
| 2625 | 2615 | psin->sin_family = AF_INET; | 
|---|
| 2626 | 2616 | psin->sin_addr.s_addr = psl->sl_addr[i]; | 
|---|
| 2627 |  | -		if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss))) | 
|---|
|  | 2617 | +		if (copy_to_user(p, &ss, sizeof(ss))) | 
|---|
| 2628 | 2618 | return -EFAULT; | 
|---|
| 2629 | 2619 | } | 
|---|
| 2630 | 2620 | return 0; | 
|---|
| 2631 |  | -done: | 
|---|
| 2632 |  | -	return err; | 
|---|
| 2633 | 2621 | } | 
|---|
| 2634 | 2622 |  | 
|---|
| 2635 | 2623 | /* | 
|---|