Possible leak of multicast source filter sctructure

Michal Ruzicka
2006-08-10T12:08:19Z

[-- Attachment #1: Type: text/plain, Size: 1610 bytes --]

Hi all!
It seems to me that there is a leak of struct ip_sf_socklist in the
ip_mc_drop_socket function (in net/ipv4/igmp.c) which is called on socket
close.

This patch corrects it:

diff -Naur linux-2.6.17.8.orig/net/ipv4/igmp.c
linux-2.6.17.8/net/ipv4/igmp.c
--- linux-2.6.17.8.orig/net/ipv4/igmp.c 2006-08-07 06:18:54.000000000 +0200
+++ linux-2.6.17.8/net/ipv4/igmp.c 2006-08-10 10:38:04.000000000 +0200
@@ -2206,9 +2206,10 @@
(void) ip_mc_leave_src(sk, iml, in_dev);
ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
in_dev_put(in_dev);
- }
- sock_kfree_s(sk, iml, sizeof(*iml));
+ } else if (iml->sflist != NULL)
+ sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max));

+ sock_kfree_s(sk, iml, sizeof(*iml));
}
rtnl_unlock();
}

The leak only happens if there are some multicast source filters set on a
socket wich are bound to an interface that does not exist any more, as in
the following scenario:
1. create a temporary interface (say GRE tunnel)
3. join a multicast group an set a source filter on the temporary interface
via MCAST_JOIN_SOURCE_GROUP setsockopt call
4. destroy the temporary interface
5. close the socket

This sequence of things eventually leads to a call of ip_mc_drop_socket
function, which fails to free the soucre filter structure ip_sf_socklist
pointed to from members of socket's multicast addresses list. This structure
is normally freed in ip_mc_leave_src function but this function is not
called in this scenario because the interface that the multicast group is
joined on does not exist any more.

Thanks
Michal Ruzicka

[-- Attachment #2: linux-2.6.17.8-mc_sf_leak.patch --]
[-- Type: application/octet-stream, Size: 609 bytes --]

diff -Naur linux-2.6.17.8.orig/net/ipv4/igmp.c linux-2.6.17.8/net/ipv4/igmp.c
--- linux-2.6.17.8.orig/net/ipv4/igmp.c 2006-08-07 06:18:54.000000000 +0200
+++ linux-2.6.17.8/net/ipv4/igmp.c 2006-08-10 10:38:04.000000000 +0200
@@ -2206,9 +2206,10 @@
(void) ip_mc_leave_src(sk, iml, in_dev);
ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
in_dev_put(in_dev);
- }
- sock_kfree_s(sk, iml, sizeof(*iml));
+ } else if (iml->sflist != NULL)
+ sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max));

+ sock_kfree_s(sk, iml, sizeof(*iml));
}
rtnl_unlock();
}