From: Al Viro <v...@zeniv.linux.org.uk>

Native ->setsockopt() handling of these options (MCAST_..._SOURCE_GROUP
and MCAST_{,UN}BLOCK_SOURCE) consists of copyin + call of a helper that
does the actual work.  The only change needed for ->compat_setsockopt()
is a slightly different copyin - the helpers can be reused as-is.

Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>
---
 net/ipv4/ip_sockglue.c   | 23 +++++++++++++++++++++--
 net/ipv6/ipv6_sockglue.c | 23 +++++++++++++++++++++--
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 4f412b0bdda4..8a3b879dc0f5 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1322,8 +1322,27 @@ int compat_ip_setsockopt(struct sock *sk, int level, int 
optname,
        case MCAST_LEAVE_SOURCE_GROUP:
        case MCAST_BLOCK_SOURCE:
        case MCAST_UNBLOCK_SOURCE:
-               return compat_mc_setsockopt(sk, level, optname, optval, optlen,
-                       ip_setsockopt);
+       {
+               struct compat_group_source_req __user *gsr32 = (void __user 
*)optval;
+               struct group_source_req greqs;
+
+               if (optlen != sizeof(struct compat_group_source_req))
+                       return -EINVAL;
+
+               if (get_user(greqs.gsr_interface, &gsr32->gsr_interface) ||
+                   copy_from_user(&greqs.gsr_group, &gsr32->gsr_group,
+                               sizeof(greqs.gsr_group)) ||
+                   copy_from_user(&greqs.gsr_source, &gsr32->gsr_source,
+                               sizeof(greqs.gsr_source)))
+                       return -EFAULT;
+
+               rtnl_lock();
+               lock_sock(sk);
+               err = do_mcast_group_source(sk, optname, &greqs);
+               release_sock(sk);
+               rtnl_unlock();
+               return err;
+       }
        case MCAST_MSFILTER:
        {
                const int size0 = offsetof(struct compat_group_filter, 
gf_slist);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index fc525ad9ed3c..4c9a9f2f83cf 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1015,8 +1015,27 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, 
int optname,
        case MCAST_LEAVE_SOURCE_GROUP:
        case MCAST_BLOCK_SOURCE:
        case MCAST_UNBLOCK_SOURCE:
-               return compat_mc_setsockopt(sk, level, optname, optval, optlen,
-                       ipv6_setsockopt);
+       {
+               struct compat_group_source_req __user *gsr32 = (void __user 
*)optval;
+               struct group_source_req greqs;
+
+               if (optlen < sizeof(struct compat_group_source_req))
+                       return -EINVAL;
+
+               if (get_user(greqs.gsr_interface, &gsr32->gsr_interface) ||
+                   copy_from_user(&greqs.gsr_group, &gsr32->gsr_group,
+                               sizeof(greqs.gsr_group)) ||
+                   copy_from_user(&greqs.gsr_source, &gsr32->gsr_source,
+                               sizeof(greqs.gsr_source)))
+                       return -EFAULT;
+
+               rtnl_lock();
+               lock_sock(sk);
+               err = do_ipv6_mcast_group_source(sk, optname, &greqs);
+               release_sock(sk);
+               rtnl_unlock();
+               return err;
+       }
        case MCAST_MSFILTER:
        {
                const int size0 = offsetof(struct compat_group_filter, 
gf_slist);
-- 
2.11.0

Reply via email to