Skip to content

Commit 2e04172

Browse files
author
Al Viro
committed
ipv4: do compat setsockopt for MCAST_MSFILTER directly
Parallel to what the native setsockopt() does, except that unlike the native setsockopt() we do not use memdup_user() - we want the sockaddr_storage fields properly aligned, so we allocate 4 bytes more and copy compat_group_filter at the offset 4, which yields the proper alignments. Signed-off-by: Al Viro <[email protected]>
1 parent e986d4d commit 2e04172

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

net/ipv4/ip_sockglue.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,9 +1286,55 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
12861286
case MCAST_LEAVE_SOURCE_GROUP:
12871287
case MCAST_BLOCK_SOURCE:
12881288
case MCAST_UNBLOCK_SOURCE:
1289-
case MCAST_MSFILTER:
12901289
return compat_mc_setsockopt(sk, level, optname, optval, optlen,
12911290
ip_setsockopt);
1291+
case MCAST_MSFILTER:
1292+
{
1293+
const int size0 = offsetof(struct compat_group_filter, gf_slist);
1294+
struct compat_group_filter *gf32;
1295+
void *p;
1296+
int n;
1297+
1298+
if (optlen < size0)
1299+
return -EINVAL;
1300+
if (optlen > sysctl_optmem_max - 4)
1301+
return -ENOBUFS;
1302+
1303+
p = kmalloc(optlen + 4, GFP_KERNEL);
1304+
if (!p)
1305+
return -ENOMEM;
1306+
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
1307+
if (copy_from_user(gf32, optval, optlen)) {
1308+
err = -EFAULT;
1309+
goto mc_msf_out;
1310+
}
1311+
1312+
n = gf32->gf_numsrc;
1313+
/* numsrc >= (4G-140)/128 overflow in 32 bits */
1314+
if (n >= 0x1ffffff) {
1315+
err = -ENOBUFS;
1316+
goto mc_msf_out;
1317+
}
1318+
if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen) {
1319+
err = -EINVAL;
1320+
goto mc_msf_out;
1321+
}
1322+
1323+
rtnl_lock();
1324+
lock_sock(sk);
1325+
/* numsrc >= (4G-140)/128 overflow in 32 bits */
1326+
if (n > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
1327+
err = -ENOBUFS;
1328+
else
1329+
err = set_mcast_msfilter(sk, gf32->gf_interface,
1330+
n, gf32->gf_fmode,
1331+
&gf32->gf_group, gf32->gf_slist);
1332+
release_sock(sk);
1333+
rtnl_unlock();
1334+
mc_msf_out:
1335+
kfree(p);
1336+
return err;
1337+
}
12921338
}
12931339

12941340
err = do_ip_setsockopt(sk, level, optname, optval, optlen);

0 commit comments

Comments
 (0)