diff -Niur linux-2.4.22/net/ipv4/ip_sockglue.c linux-2.4.26/net/ipv4/ip_sockglue.c --- linux-2.4.22/net/ipv4/ip_sockglue.c Mon Aug 25 13:44:44 2003 +++ linux-2.4.26/net/ipv4/ip_sockglue.c Wed Apr 14 15:05:41 2004 @@ -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; } diff -Niur linux-2.4.22/net/ipv6/ipv6_sockglue.c linux-2.4.26/net/ipv6/ipv6_sockglue.c --- linux-2.4.22/net/ipv6/ipv6_sockglue.c Mon Aug 25 13:44:44 2003 +++ linux-2.4.26/net/ipv6/ipv6_sockglue.c Wed Apr 14 15:05:41 2004 @@ -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);