mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
net: Add compat support for getsockopt (MCAST_MSFILTER)
This patch adds support for getsockopt for MCAST_MSFILTER for both IPv4 and IPv6. It depends on the previous setsockopt patch, and uses the same method. Signed-off-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
be666e0a13
commit
42908c69f6
@ -42,5 +42,8 @@ extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsi
|
|||||||
|
|
||||||
extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int,
|
extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int,
|
||||||
int (*)(struct sock *, int, int, char __user *, int));
|
int (*)(struct sock *, int, int, char __user *, int));
|
||||||
|
extern int compat_mc_getsockopt(struct sock *, int, int, char __user *,
|
||||||
|
int __user *, int (*)(struct sock *, int, int, char __user *,
|
||||||
|
int __user *));
|
||||||
|
|
||||||
#endif /* NET_COMPAT_H */
|
#endif /* NET_COMPAT_H */
|
||||||
|
79
net/compat.c
79
net/compat.c
@ -640,6 +640,85 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
|
|||||||
|
|
||||||
EXPORT_SYMBOL(compat_mc_setsockopt);
|
EXPORT_SYMBOL(compat_mc_setsockopt);
|
||||||
|
|
||||||
|
int compat_mc_getsockopt(struct sock *sock, int level, int optname,
|
||||||
|
char __user *optval, int __user *optlen,
|
||||||
|
int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
|
||||||
|
{
|
||||||
|
struct compat_group_filter __user *gf32 = (void *)optval;
|
||||||
|
struct group_filter __user *kgf;
|
||||||
|
int __user *koptlen;
|
||||||
|
u32 interface, fmode, numsrc;
|
||||||
|
int klen, ulen, err;
|
||||||
|
|
||||||
|
if (optname != MCAST_MSFILTER)
|
||||||
|
return getsockopt(sock, level, optname, optval, optlen);
|
||||||
|
|
||||||
|
koptlen = compat_alloc_user_space(sizeof(*koptlen));
|
||||||
|
if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
|
||||||
|
__get_user(ulen, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* adjust len for pad */
|
||||||
|
klen = ulen + sizeof(*kgf) - sizeof(*gf32);
|
||||||
|
|
||||||
|
if (klen < GROUP_FILTER_SIZE(0))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
|
||||||
|
__put_user(klen, koptlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* have to allow space for previous compat_alloc_user_space, too */
|
||||||
|
kgf = compat_alloc_user_space(klen+sizeof(*optlen));
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
|
||||||
|
__get_user(interface, &gf32->gf_interface) ||
|
||||||
|
__get_user(fmode, &gf32->gf_fmode) ||
|
||||||
|
__get_user(numsrc, &gf32->gf_numsrc) ||
|
||||||
|
__put_user(interface, &kgf->gf_interface) ||
|
||||||
|
__put_user(fmode, &kgf->gf_fmode) ||
|
||||||
|
__put_user(numsrc, &kgf->gf_numsrc) ||
|
||||||
|
copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
|
||||||
|
__get_user(klen, koptlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
|
||||||
|
__put_user(ulen, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, kgf, klen) ||
|
||||||
|
!access_ok(VERIFY_WRITE, gf32, ulen) ||
|
||||||
|
__get_user(interface, &kgf->gf_interface) ||
|
||||||
|
__get_user(fmode, &kgf->gf_fmode) ||
|
||||||
|
__get_user(numsrc, &kgf->gf_numsrc) ||
|
||||||
|
__put_user(interface, &gf32->gf_interface) ||
|
||||||
|
__put_user(fmode, &gf32->gf_fmode) ||
|
||||||
|
__put_user(numsrc, &gf32->gf_numsrc))
|
||||||
|
return -EFAULT;
|
||||||
|
if (numsrc) {
|
||||||
|
int copylen;
|
||||||
|
|
||||||
|
klen -= GROUP_FILTER_SIZE(0);
|
||||||
|
copylen = numsrc * sizeof(gf32->gf_slist[0]);
|
||||||
|
if (copylen > klen)
|
||||||
|
copylen = klen;
|
||||||
|
if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(compat_mc_getsockopt);
|
||||||
|
|
||||||
|
|
||||||
/* Argument list sizes for compat_sys_socketcall */
|
/* Argument list sizes for compat_sys_socketcall */
|
||||||
#define AL(x) ((x) * sizeof(u32))
|
#define AL(x) ((x) * sizeof(u32))
|
||||||
|
@ -1186,7 +1186,14 @@ int ip_getsockopt(struct sock *sk, int level,
|
|||||||
int compat_ip_getsockopt(struct sock *sk, int level, int optname,
|
int compat_ip_getsockopt(struct sock *sk, int level, int optname,
|
||||||
char __user *optval, int __user *optlen)
|
char __user *optval, int __user *optlen)
|
||||||
{
|
{
|
||||||
int err = do_ip_getsockopt(sk, level, optname, optval, optlen);
|
int err;
|
||||||
|
|
||||||
|
if (optname == MCAST_MSFILTER)
|
||||||
|
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
|
||||||
|
ip_getsockopt);
|
||||||
|
|
||||||
|
err = do_ip_getsockopt(sk, level, optname, optval, optlen);
|
||||||
|
|
||||||
#ifdef CONFIG_NETFILTER
|
#ifdef CONFIG_NETFILTER
|
||||||
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
||||||
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
|
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
|
||||||
|
@ -1089,6 +1089,10 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|||||||
if(level != SOL_IPV6)
|
if(level != SOL_IPV6)
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
|
|
||||||
|
if (optname == MCAST_MSFILTER)
|
||||||
|
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
|
||||||
|
ipv6_getsockopt);
|
||||||
|
|
||||||
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
|
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
|
||||||
#ifdef CONFIG_NETFILTER
|
#ifdef CONFIG_NETFILTER
|
||||||
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
||||||
|
Loading…
Reference in New Issue
Block a user