Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit acd6e00b authored by David L Stevens's avatar David L Stevens Committed by David S. Miller
Browse files

[MCAST]: Fix filter leak on device removal.



This fixes source filter leakage when a device is removed and a
process leaves the group thereafter.

This also includes corresponding fixes for IPv6 multicast source
filters on device removal.

Signed-off-by: default avatarDavid L Stevens <dlstevens@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c7fa9d18
Loading
Loading
Loading
Loading
+19 −13
Original line number Original line Diff line number Diff line
@@ -1793,29 +1793,35 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
	struct in_device *in_dev;
	struct in_device *in_dev;
	u32 group = imr->imr_multiaddr.s_addr;
	u32 group = imr->imr_multiaddr.s_addr;
	u32 ifindex;
	u32 ifindex;
	int ret = -EADDRNOTAVAIL;


	rtnl_lock();
	rtnl_lock();
	in_dev = ip_mc_find_dev(imr);
	in_dev = ip_mc_find_dev(imr);
	if (!in_dev) {
		rtnl_unlock();
		return -ENODEV;
	}
	ifindex = imr->imr_ifindex;
	ifindex = imr->imr_ifindex;
	for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
	for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
		if (iml->multi.imr_multiaddr.s_addr == group &&
		if (iml->multi.imr_multiaddr.s_addr != group)
		    iml->multi.imr_ifindex == ifindex) {
			continue;
		if (ifindex) {
			if (iml->multi.imr_ifindex != ifindex)
				continue;
		} else if (imr->imr_address.s_addr && imr->imr_address.s_addr !=
				iml->multi.imr_address.s_addr)
			continue;

		(void) ip_mc_leave_src(sk, iml, in_dev);
		(void) ip_mc_leave_src(sk, iml, in_dev);


		*imlp = iml->next;
		*imlp = iml->next;


		if (in_dev)
			ip_mc_dec_group(in_dev, group);
			ip_mc_dec_group(in_dev, group);
		rtnl_unlock();
		rtnl_unlock();
		sock_kfree_s(sk, iml, sizeof(*iml));
		sock_kfree_s(sk, iml, sizeof(*iml));
		return 0;
		return 0;
	}
	}
	}
	if (!in_dev)
		ret = -ENODEV;
	rtnl_unlock();
	rtnl_unlock();
	return -EADDRNOTAVAIL;
	return ret;
}
}


int ip_mc_source(int add, int omode, struct sock *sk, struct
int ip_mc_source(int add, int omode, struct sock *sk, struct
+6 −4
Original line number Original line Diff line number Diff line
@@ -268,13 +268,14 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
			if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) {
			if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) {
				struct inet6_dev *idev = in6_dev_get(dev);
				struct inet6_dev *idev = in6_dev_get(dev);


				if (idev) {
				(void) ip6_mc_leave_src(sk, mc_lst, idev);
				(void) ip6_mc_leave_src(sk, mc_lst, idev);
				if (idev) {
					__ipv6_dev_mc_dec(idev, &mc_lst->addr);
					__ipv6_dev_mc_dec(idev, &mc_lst->addr);
					in6_dev_put(idev);
					in6_dev_put(idev);
				}
				}
				dev_put(dev);
				dev_put(dev);
			}
			} else
				(void) ip6_mc_leave_src(sk, mc_lst, NULL);
			sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
			sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
			return 0;
			return 0;
		}
		}
@@ -334,13 +335,14 @@ void ipv6_sock_mc_close(struct sock *sk)
		if (dev) {
		if (dev) {
			struct inet6_dev *idev = in6_dev_get(dev);
			struct inet6_dev *idev = in6_dev_get(dev);


			if (idev) {
			(void) ip6_mc_leave_src(sk, mc_lst, idev);
			(void) ip6_mc_leave_src(sk, mc_lst, idev);
			if (idev) {
				__ipv6_dev_mc_dec(idev, &mc_lst->addr);
				__ipv6_dev_mc_dec(idev, &mc_lst->addr);
				in6_dev_put(idev);
				in6_dev_put(idev);
			}
			}
			dev_put(dev);
			dev_put(dev);
		}
		} else
			(void) ip6_mc_leave_src(sk, mc_lst, NULL);


		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));