--- linux-2.4.22/include/linux/sysctl.h	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/include/linux/sysctl.h	2004-04-14 22:05:40.000000000 +0900
@@ -391,7 +391,8 @@
 	NET_IPV6_NEIGH=17,
 	NET_IPV6_ROUTE=18,
 	NET_IPV6_ICMP=19,
-	NET_IPV6_BINDV6ONLY=20
+	NET_IPV6_BINDV6ONLY=20,
+	NET_IPV6_MLD_MAX_MSF=25,
 };
 
 enum {
--- linux-2.4.22/include/net/ipv6.h	2003-06-13 23:51:39.000000000 +0900
+++ linux-2.4.26/include/net/ipv6.h	2004-04-14 22:05:40.000000000 +0900
@@ -104,6 +104,7 @@
 
 /* sysctls */
 extern int sysctl_ipv6_bindv6only;
+extern int sysctl_mld_max_msf;
 
 extern struct ipv6_mib		ipv6_statistics[NR_CPUS*2];
 #define IP6_INC_STATS(field)		SNMP_INC_STATS(ipv6_statistics, field)
--- linux-2.4.22/net/ipv4/ip_sockglue.c	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/net/ipv4/ip_sockglue.c	2004-04-14 22:05:41.000000000 +0900
@@ -608,10 +608,16 @@
 		}
 		case IP_MSFILTER:
 		{
+			extern int sysctl_optmem_max;
+			extern int sysctl_igmp_max_msf;
 			struct ip_msfilter *msf;
 
 			if (optlen < IP_MSFILTER_SIZE(0))
 				goto e_inval;
+			if (optlen > sysctl_optmem_max) {
+				err = -ENOBUFS;
+				break;
+			}
 			msf = (struct ip_msfilter *)kmalloc(optlen, GFP_KERNEL);
 			if (msf == 0) {
 				err = -ENOBUFS;
@@ -622,6 +628,18 @@
 				kfree(msf);
 				break;
 			}
+			/* numsrc >= (1G-4) overflow in 32 bits */
+			if (msf->imsf_numsrc >= 0x3ffffffcU ||
+			    msf->imsf_numsrc > sysctl_igmp_max_msf) {
+				kfree(msf);
+				err = -ENOBUFS;
+				break;
+			}
+			if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
+				kfree(msf);
+				err = -EINVAL;
+				break;
+			}
 			err = ip_mc_msfilter(sk, msf, 0);
 			kfree(msf);
 			break;
@@ -744,6 +762,8 @@
 		}
 		case MCAST_MSFILTER:
 		{
+			extern int sysctl_optmem_max;
+			extern int sysctl_igmp_max_msf;
 			struct sockaddr_in *psin;
 			struct ip_msfilter *msf = 0;
 			struct group_filter *gsf = 0;
@@ -751,6 +771,10 @@
 
 			if (optlen < GROUP_FILTER_SIZE(0))
 				goto e_inval;
+			if (optlen > sysctl_optmem_max) {
+				err = -ENOBUFS;
+				break;
+			}
 			gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
 			if (gsf == 0) {
 				err = -ENOBUFS;
@@ -760,7 +784,13 @@
 			if (copy_from_user(gsf, optval, optlen)) {
 				goto mc_msf_out;
 			}
-			if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) {
+			/* numsrc >= (4G-140)/128 overflow in 32 bits */
+			if (gsf->gf_numsrc >= 0x1ffffff ||
+			    gsf->gf_numsrc > sysctl_igmp_max_msf) {
+				err = -ENOBUFS;
+				goto mc_msf_out;
+			}
+			if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
 				err = EINVAL;
 				goto mc_msf_out;
 			}
--- linux-2.4.22/net/ipv6/ipv6_sockglue.c	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/net/ipv6/ipv6_sockglue.c	2004-04-14 22:05:41.000000000 +0900
@@ -452,10 +452,16 @@
 	}
 	case MCAST_MSFILTER:
 	{
+		extern int sysctl_optmem_max;
+		extern int sysctl_mld_max_msf;
 		struct group_filter *gsf;
 
 		if (optlen < GROUP_FILTER_SIZE(0))
 			goto e_inval;
+		if (optlen > sysctl_optmem_max) {
+			retv = -ENOBUFS;
+			break;
+		}
 		gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
 		if (gsf == 0) {
 			retv = -ENOBUFS;
@@ -466,6 +472,18 @@
 			kfree(gsf);
 			break;
 		}
+		/* numsrc >= (4G-140)/128 overflow in 32 bits */
+		if (gsf->gf_numsrc >= 0x1ffffffU ||
+		    gsf->gf_numsrc > sysctl_mld_max_msf) {
+			kfree(gsf);
+			retv = -ENOBUFS;
+			break;
+		}
+		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
+			kfree(gsf);
+			retv = -EINVAL;
+			break;
+		}
 		retv = ip6_mc_msfilter(sk, gsf);
 		kfree(gsf);
 
--- linux-2.4.22/net/ipv6/mcast.c	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/net/ipv6/mcast.c	2004-04-14 22:05:41.000000000 +0900
@@ -160,6 +163,10 @@
 #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
 #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
 
+#define IPV6_MLD_MAX_MSF	10
+
+int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF;
+
 /*
  *	socket join on multicast group
  */
@@ -398,6 +405,10 @@
 	}
 	/* else, add a new source to the filter */
 
+	if (psl && psl->sl_count >= sysctl_mld_max_msf) {
+		err = -ENOBUFS;
+		goto done;
+	}
 	if (!psl || psl->sl_count == psl->sl_max) {
 		struct ip6_sf_socklist *newpsl;
 		int count = IP6_SFBLOCK;
@@ -604,9 +615,9 @@
 			if (ipv6_addr_cmp(&psl->sl_addr[i], src_addr) == 0)
 				break;
 		}
-		if (mc->sfmode == MCAST_INCLUDE && i >= psl->sl_count);
+		if (mc->sfmode == MCAST_INCLUDE && i >= psl->sl_count)
 			rv = 0;
-		if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count);
+		if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
 			rv = 0;
 	}
 	read_unlock(&ipv6_sk_mc_lock);
--- linux-2.4.22/net/ipv6/sysctl_net_ipv6.c	2003-06-13 23:51:39.000000000 +0900
+++ linux-2.4.26/net/ipv6/sysctl_net_ipv6.c	2004-04-14 22:05:41.000000000 +0900
@@ -24,6 +24,8 @@
 	{NET_IPV6_ICMP, "icmp", NULL, 0, 0500, ipv6_icmp_table},
 	{NET_IPV6_BINDV6ONLY, "bindv6only",
 	 &sysctl_ipv6_bindv6only, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV6_MLD_MAX_MSF, "mld_max_msf",
+	 &sysctl_mld_max_msf, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
--- linux-2.4.22/net/ipv4/igmp.c	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/net/ipv4/igmp.c	2004-04-14 22:05:41.000000000 +0900
@@ -101,7 +101,8 @@
 #endif
 
 
-#define IP_MAX_MEMBERSHIPS 20
+#define IP_MAX_MEMBERSHIPS	20
+#define IP_MAX_MSF		10
 
 #ifdef CONFIG_IP_MULTICAST
 /* Parameter names and values are taken from igmp-v2-06 draft */
@@ -1300,6 +1315,7 @@
  *	Join a socket to a group
  */
 int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
+int sysctl_igmp_max_msf = IP_MAX_MSF;
 
 
 static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
@@ -1760,6 +1777,10 @@
 	}
 	/* else, add a new source to the filter */
 
+	if (psl && psl->sl_count >= sysctl_igmp_max_msf) {
+		err = -ENOBUFS;
+		goto done;
+	}
 	if (!psl || psl->sl_count == psl->sl_max) {
 		struct ip_sf_socklist *newpsl;
 		int count = IP_SFBLOCK;
--- linux-2.4.22/net/netsyms.c	2003-08-25 20:44:44.000000000 +0900
+++ linux-2.4.26/net/netsyms.c	2004-04-14 22:05:41.000000000 +0900
@@ -39,6 +40,7 @@
 #ifdef CONFIG_NET
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
+extern int sysctl_optmem_max;
 #endif
 
 #ifdef CONFIG_INET
@@ -546,6 +551,7 @@
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
+EXPORT_SYMBOL(sysctl_optmem_max);
 #ifdef CONFIG_INET
 EXPORT_SYMBOL(sysctl_ip_default_ttl);
 #endif
