lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 24 Apr 2008 13:01:43 -0700
From:	David Stevens <dlstevens@...ibm.com>
To:	YOSHIFUJI Hideaki / 吉藤英明 
	<yoshfuji@...ux-ipv6.org>
Cc:	davem@...emloft.net, netdev@...r.kernel.org
Subject: Re: [GIT PULL] [IPV6] COMPAT: Fix SSM applications on 64bit kernels.

[comments in-line, where there are no leading ">", with some deleted, but 
I hope
enough for context]

YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@...ux-ipv6.org> wrote on 04/24/2008 
11:46:04 AM:


> commit afdf2703bd9423a62cf7d984bdc88273fa205033
> Author: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> Date:   Tue Apr 22 12:14:20 2008 +0900
> 
>     [IPV6] MCAST: Move mode check for group_source_req{}-sockopt to 
net/ipv6/mcast.c.
> 
>     Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> 
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index 49c4898..aa81120 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -565,7 +565,7 @@ extern const struct proto_ops inet6_dgram_ops;
>  struct group_source_req;
>  struct group_filter;
> 
> -extern int ip6_mc_source(int add, int omode, struct sock *sk,
> +extern int ip6_mc_source(struct sock *sk, int optname,
>            struct group_source_req *pgsr);
>  extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
>  extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index a53aed4..694e031 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -542,7 +542,6 @@ done:
>     case MCAST_UNBLOCK_SOURCE:
>     {
>        struct group_source_req greqs;
> -      int omode, add;
> 
>        if (optlen < sizeof(struct group_source_req))
>           goto e_inval;
> @@ -550,33 +549,7 @@ done:
>           retv = -EFAULT;
>           break;
>        }
> -      if (greqs.gsr_group.ss_family != AF_INET6 ||
> -          greqs.gsr_source.ss_family != AF_INET6) {
> -         retv = -EADDRNOTAVAIL;
> -         break;
> -      }
> -      if (optname == MCAST_BLOCK_SOURCE) {
> -         omode = MCAST_EXCLUDE;
> -         add = 1;
> -      } else if (optname == MCAST_UNBLOCK_SOURCE) {
> -         omode = MCAST_EXCLUDE;
> -         add = 0;
> -      } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
> -         struct sockaddr_in6 *psin6;
> -
> -         psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
> -         retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
> -            &psin6->sin6_addr);
> -         /* prior join w/ different source is ok */
> -         if (retv && retv != -EADDRINUSE)
> -            break;
> -         omode = MCAST_INCLUDE;
> -         add = 1;
> -      } else /* MCAST_LEAVE_SOURCE_GROUP */ {
> -         omode = MCAST_INCLUDE;
> -         add = 0;
> -      }
> -      retv = ip6_mc_source(add, omode, sk, &greqs);
> +      retv = ip6_mc_source(sk, optname, &greqs);
>        break;
>     }
>     case MCAST_MSFILTER:
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index 54f91ef..5d8d653 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -355,8 +355,8 @@ void ipv6_sock_mc_close(struct sock *sk)
>     write_unlock_bh(&ipv6_sk_mc_lock);
>  }
> 
> -int ip6_mc_source(int add, int omode, struct sock *sk,
> -   struct group_source_req *pgsr)
> +static int __ip6_mc_source(int add, int omode, struct sock *sk,
> +            struct group_source_req *pgsr)
>  {
>     struct in6_addr *source, *group;
>     struct ipv6_mc_socklist *pmc;
> @@ -496,6 +496,40 @@ done:
>     return err;
>  }
> 
> +int ip6_mc_source(struct sock *sk, int optname,
> +        struct group_source_req *pgsr)
> +{
> +   int omode, add, retv;
> +
> +   if (pgsr->gsr_group.ss_family != AF_INET6 ||
> +       pgsr->gsr_source.ss_family != AF_INET6)
> +      return -EADDRNOTAVAIL;
> +
> +   if (optname == MCAST_BLOCK_SOURCE) {
> +      omode = MCAST_EXCLUDE;
> +      add = 1;
> +   } else if (optname == MCAST_UNBLOCK_SOURCE) {
> +      omode = MCAST_EXCLUDE;
> +      add = 0;
> +   } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
> +      struct sockaddr_in6 *psin6;
> +
> +      psin6 = (struct sockaddr_in6 *)&pgsr->gsr_group;
> +      retv = ipv6_sock_mc_join(sk, pgsr->gsr_interface,
> +                &psin6->sin6_addr);
> +      /* prior join w/ different source is ok */
> +      if (retv && retv != -EADDRINUSE)
> +         return retv;
> +      omode = MCAST_INCLUDE;
> +      add = 1;
> +   } else /* MCAST_LEAVE_SOURCE_GROUP */ {
> +      omode = MCAST_INCLUDE;
> +      add = 0;
> +   }
> +
> +   return __ip6_mc_source(add, omode, sk, pgsr);
> +}
> +
>  int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
>  {
>     struct in6_addr *group;
> 

        I think this part isn't relevant to compat support, right?
I don't see much advantage in moving this, but it should be a
separate patch and discussion, I think.

> +   switch (optname) {
> +   case MCAST_JOIN_SOURCE_GROUP:
> +   case MCAST_LEAVE_SOURCE_GROUP:
> +   case MCAST_BLOCK_SOURCE:
> +   case MCAST_UNBLOCK_SOURCE:
> +       {
> +      struct group_source_req greqs;

        Are you sure we want this on the kernel stack?

> 
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index b7ae360..30e6ca1 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -744,6 +744,32 @@ compat_do_ipv6_setsockopt(struct sock *sk, int 
level, int optname,
>     int retv;
> 
>     switch (optname) {
> +   case MCAST_JOIN_GROUP:
> +   case MCAST_LEAVE_GROUP:
> +       {
> +      struct group_req greq;

        Big for the kernel stack.


> commit 3c055f969f7f3716f6846037c2ec0fa06e0424b3
> Author: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> Date:   Thu Apr 24 17:32:10 2008 +0900
> 
>     [IPV6] COMPAT: group_filter{}-setsockopt compat layer.
> 
>     Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> 
> diff --git a/include/linux/in.h b/include/linux/in.h
> index 2fbd7c7..ccbfc76 100644
> --- a/include/linux/in.h
> +++ b/include/linux/in.h
> @@ -182,6 +182,19 @@ struct compat_group_req
>     __u32                gr_interface;
>     struct __compat_sockaddr_storage    gr_group;
>  };
> +
> +struct compat_group_filter
> +{
> +   __u32               gf_interface;
> +   struct __compat_sockaddr_storage   gf_group;
> +   __u32               gf_fmode;
> +   __u32               gf_numsrc;
> +   struct __compat_sockaddr_storage   gf_slist[1];
> +};
> +
> +#define COMPAT_GROUP_FILTER_SIZE(numsrc) \
> +   (sizeof(struct compat_group_filter) - sizeof(struct 
__compat_sockaddr_storage) \
> +   + (numsrc) * sizeof(struct __compat_sockaddr_storage))
>  #endif
>  #endif

        Better to compute this just once, in which case no macro needed.
Suggest a variable and do
"len = GROUP_FILTER_SIZE(numsrc) + sizeof(struct compat_group_filter) - 
sizeof(struct group_filter);"
Also, why put these in an include file when there is only one use?

> 
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index 30e6ca1..0895e7d 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -794,6 +794,57 @@ compat_do_ipv6_setsockopt(struct sock *sk, int 
level, int optname,
>        retv = ip6_mc_source(sk, optname, &greqs);
>        break;
>         }
> +   case MCAST_MSFILTER:
> +       {
> +      extern int sysctl_mld_max_msf;
> +      struct compat_group_filter __user *ugsf = (void __user *)optval;
> +      struct group_filter *gsf;
> +      u32 gf_numsrc;
> +      int i;
> +
> +      if (optlen < COMPAT_GROUP_FILTER_SIZE(0))
> +         return -EINVAL;
> +
> +      if (access_ok(VERIFY_READ, ugsf, COMPAT_GROUP_FILTER_SIZE(0)) ||
> +          __get_user(gf_numsrc, &ugsf->gf_numsrc))
> +         return -EFAULT;
> +
> +      if (COMPAT_GROUP_FILTER_SIZE(gf_numsrc) > optlen)
> +         return -EINVAL;
> +
> +      if (optlen > sysctl_optmem_max ||
> +          gf_numsrc >= 0x1ffffffU ||
> +          gf_numsrc > sysctl_mld_max_msf)
> +         return -ENOBUFS;

        Missing comment from the original that explains the significance
of "0x1ffffffU", and the version I'm looking at doesn't have the
sysctl_optmem_max check. Though it can be raised, without the check,
we can support very large filters too. Maybe ok, but unrelated to
compat support.

> +
> +      optlen = GROUP_FILTER_SIZE(gf_numsrc);
> +      gsf = kmalloc(optlen, GFP_KERNEL);
> +      if (!gsf) {
> +         retv = -ENOBUFS;
> +         break;
> +      }
> +      retv = -EFAULT;
> +      if (__get_user(gsf->gf_interface, &ugsf->gf_interface) ||
> +          __copy_from_user(&gsf->gf_group, &ugsf->gf_group, 
sizeof(gsf->gf_group)) ||
> +          __get_user(gsf->gf_fmode, &ugsf->gf_fmode) ||
> +          access_ok(VERIFY_READ, ugsf->gf_slist,
> +               sizeof(struct __compat_sockaddr_storage) * gf_numsrc))
> +         goto kfree_out;

        Does access_ok() handle (valid) case numsrc==0 correctly?

> +
> +      gsf->gf_numsrc = gf_numsrc;
> +
> +      for (i = 0; i < gf_numsrc; i++) {
> +         if (__copy_from_user(&gsf->gf_slist[i],
> +                    &ugsf->gf_slist[i],
> +                    sizeof(gsf->gf_slist[i])))
> +            goto kfree_out;
> +      }

        This is adding a lot of separate copies that I believe
are unnecessary. sockaddr_storage is the same size, so you
can copy optlen-GROUP_FILTER_SIZE(0) all at once.

> 
> -int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
> -   struct group_filter __user *optval, int __user *optlen)
> +int __ip6_mc_msf_lookup(struct sock *sk,
> +         struct in6_addr *group, int interface,
> +         struct ip6_sf_socklist **ppsl)
>  {
> -   int err, i, count, copycount;
> -   struct in6_addr *group;
>     struct ipv6_mc_socklist *pmc;
> -   struct inet6_dev *idev;
> -   struct net_device *dev;
>     struct ipv6_pinfo *inet6 = inet6_sk(sk);
> -   struct ip6_sf_socklist *psl;
> +   struct net_device *dev;
> +   struct inet6_dev *idev;
>     struct net *net = sock_net(sk);
> +   int ret = 0;
> 
> -   group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
> -
> -   if (!ipv6_addr_is_multicast(group))
> -      return -EINVAL;
> -
> -   idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
> +   if (!ipv6_addr_is_multicast(group)) {
> +      ret = -EINVAL;
> +      goto out;
> +   }
> 
> -   if (!idev)
> -      return -ENODEV;
> +   idev = ip6_mc_find_dev(net, group, interface);
> +   if (!idev) {
> +      ret = -ENODEV;
> +      goto out;
> +   }

        Looks unrelated to compat support...? As what follows in
this function.

> 
>     dev = idev->dev;
> 
> -   err = -EADDRNOTAVAIL;
> +   ret = -EADDRNOTAVAIL;
>     /*
>      * changes to the ipv6_mc_list require the socket lock and
>      * a read lock on ip6_sk_mc_lock. We have the socket lock,
>      * so reading the list is safe.
>      */
> 
> -   for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
> -      if (pmc->ifindex != gsf->gf_interface)
> +   for (pmc = inet6->ipv6_mc_list; pmc; pmc = pmc->next) {
> +      if (pmc->ifindex != interface)
>           continue;
>        if (ipv6_addr_equal(group, &pmc->addr))
>           break;
>     }
> -   if (!pmc)      /* must have a prior join */
> -      goto done;
> -   gsf->gf_fmode = pmc->sfmode;
> -   psl = pmc->sflist;
> -   count = psl ? psl->sl_count : 0;
> +   if (pmc) {
> +      *ppsl = pmc->sflist;
> +      ret = pmc->sfmode;
> +   }
> +
>     read_unlock_bh(&idev->lock);
>     in6_dev_put(idev);
>     dev_put(dev);
> +out:
> +   return ret;
> +}
> 
> -   copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
> -   gsf->gf_numsrc = count;
> -   if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
> -       copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) {
> -      return -EFAULT;
> -   }
> -   /* changes to psl require the socket lock, a read lock on
> -    * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
> -    * have the socket lock, so reading here is safe.
> -    */
> -   for (i=0; i<copycount; i++) {
> -      struct sockaddr_in6 *psin6;
> -      struct sockaddr_storage ss;
> +int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
> +   struct group_filter __user *optval, int __user *optlen)
> +{
> +   struct in6_addr *group;
> +   struct ip6_sf_socklist *psl;
> +   int fmode;
> +
> +   group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
> +
> +   fmode = __ip6_mc_msf_lookup(sk, group, gsf->gf_interface, &psl);
> +   if (fmode < 0)
> +      return fmode;
> 
> -      psin6 = (struct sockaddr_in6 *)&ss;
> -      memset(&ss, 0, sizeof(ss));
> -      psin6->sin6_family = AF_INET6;
> -      psin6->sin6_addr = psl->sl_addr[i];
> -      if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss)))
> +   if (psl) {
> +      int count = psl ? psl->sl_count : 0;
> +      int i, copycount;
> +      struct sockaddr_in6 sin6;
> +
> +      copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
> +
> +      if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
> +          access_ok(VERIFY_WRITE, optval, GROUP_FILTER_SIZE(copycount)) 
||
> +          __put_user((u32)fmode, &optval->gf_fmode) ||
> +          __put_user((u32)count, &optval->gf_numsrc))
>           return -EFAULT;
> +
> +      /* changes to psl require the socket lock, a read lock on
> +       * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
> +       * have the socket lock, so reading here is safe.
> +       */
> +      memset(&sin6, 0, sizeof(sin6));
> +      sin6.sin6_family = AF_INET6;
> +
> +      for (i = 0; i < copycount; i++) {
> +         struct sockaddr_in6 __user *usin6 = (void __user 
*)&optval->gf_slist[i];
> +
> +         ipv6_addr_copy(&sin6.sin6_addr, &psl->sl_addr[i]);
> +
> +         if (__copy_to_user(usin6, &sin6, sizeof(sin6)) ||
> +             __clear_user(usin6 + 1, sizeof(optval->gf_slist[i]) - 
sizeof(*usin6)))
> +            return -EFAULT;
> +      }
>     }
>     return 0;
> -done:
> -   read_unlock_bh(&idev->lock);
> -   in6_dev_put(idev);
> -   dev_put(dev);
> -   return err;
>  }
> 
>  int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
> 
> ---
> commit e920bd82cbc6e0b83087513a25220e9379b24b49
> Author: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> Date:   Wed Apr 23 18:03:14 2008 +0900
> 
>     [IPV6] MCAST: Make ip6_mc_msfget() more generic.
> 
>     Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> 
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index aa81120..103272f 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -568,7 +568,9 @@ struct group_filter;
>  extern int ip6_mc_source(struct sock *sk, int optname,
>            struct group_source_req *pgsr);
>  extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
> -extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
> +extern int ip6_mc_msfget(struct sock *sk,
> +          struct in6_addr *group, u32 gf_interface,
> +          u32 gf_srcnum,
>            struct group_filter __user *optval,
>            int __user *optlen);
> 
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index 0895e7d..d670078 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -949,8 +949,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int 
level,
> int optname,
>        if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
>           return -EFAULT;
>        lock_sock(sk);
> -      err = ip6_mc_msfget(sk, &gsf,
> -         (struct group_filter __user *)optval, optlen);
> +      err = ip6_mc_msfget(sk,
> +                &((struct sockaddr_in6 *)&gsf.gf_group)->sin6_addr,
> +                gsf.gf_interface, gsf.gf_numsrc,
> +                (struct group_filter __user *)optval, optlen);
>        release_sock(sk);
>        return err;
>     }
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index d32d6a3..b781192 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -670,16 +670,14 @@ out:
>     return ret;
>  }
> 
> -int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
> -   struct group_filter __user *optval, int __user *optlen)
> +int ip6_mc_msfget(struct sock *sk,
> +        struct in6_addr *group, u32 gf_interface, u32 gf_numsrc,
> +        struct group_filter __user *optval, int __user *optlen)
>  {
> -   struct in6_addr *group;
>     struct ip6_sf_socklist *psl;
>     int fmode;
> 
> -   group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
> -
> -   fmode = __ip6_mc_msf_lookup(sk, group, gsf->gf_interface, &psl);
> +   fmode = __ip6_mc_msf_lookup(sk, group, gf_interface, &psl);
>     if (fmode < 0)
>        return fmode;
> 
> @@ -688,7 +686,7 @@ int ip6_mc_msfget(struct sock *sk, struct 
group_filter *gsf,
>        int i, copycount;
>        struct sockaddr_in6 sin6;
> 
> -      copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
> +      copycount = count < gf_numsrc ? count : gf_numsrc;
> 
>        if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
>            access_ok(VERIFY_WRITE, optval, GROUP_FILTER_SIZE(copycount)) 
||
> 
> ---
> commit 9153c1a545f2366f57bf46bcd59d5b99d61016f7
> Author: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> Date:   Thu Apr 24 17:51:30 2008 +0900
> 
>     [IPV6] COMPAT: group_filter{}-getsockopt compat layer.
> 
>     Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@...ux-ipv6.org>
> 
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index 103272f..c98c722 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -574,6 +574,16 @@ extern int ip6_mc_msfget(struct sock *sk,
>            struct group_filter __user *optval,
>            int __user *optlen);
> 
> +#ifdef CONFIG_COMPAT
> +struct compat_group_filter;
> +
> +int ip6_mc_compat_msfget(struct sock *sk,
> +          struct in6_addr *group,
> +          u32 gf_interface, u32 gf_numsrc,
> +          struct compat_group_filter __user *optval,
> +          int __user *optlen);
> +#endif
> +
>  #ifdef CONFIG_PROC_FS
>  extern int  ac6_proc_init(struct net *net);
>  extern void ac6_proc_exit(struct net *net);
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index d670078..46bafee 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -1200,7 +1200,33 @@ static int
>  compat_do_ipv6_getsockopt(struct sock *sk, int level, int optname,
>             char __user *optval, int __user *optlen)
>  {
> -   return do_ipv6_getsockopt(sk, level, optname, optval, optlen);
> +   int len, err;
> +
> +   if (get_user(len, optlen))
> +      return -EFAULT;
> +
> +   switch (optname) {
> +   case MCAST_MSFILTER:
> +       {
> +      struct compat_group_filter gsf;
> +      int err;
> +
> +      if (len < COMPAT_GROUP_FILTER_SIZE(0))
> +         return -EINVAL;
> +      if (copy_from_user(&gsf, optval, COMPAT_GROUP_FILTER_SIZE(0)))
> +         return -EFAULT;
> +      lock_sock(sk);
> +      err = ip6_mc_compat_msfget(sk,
> +                  &((struct sockaddr_in6 *)&gsf.gf_group)->sin6_addr,
> +                  gsf.gf_interface, gsf.gf_numsrc,
> +                  (struct compat_group_filter __user *)optval,
> +                  optlen);
> +      release_sock(sk);
> +       }
> +   default:
> +      err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
> +   }
> +   return err;
>  }
> 
>  int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index b781192..bdfabbb 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -714,6 +714,54 @@ int ip6_mc_msfget(struct sock *sk,
>     return 0;
>  }
> 
> +#ifdef CONFIG_COMPAT
> +int ip6_mc_compat_msfget(struct sock *sk,
> +          struct in6_addr *group,
> +          u32 gf_interface, u32 gf_numsrc,
> +          struct compat_group_filter __user *optval,
> +          int __user *optlen)
> +{
> +   struct ip6_sf_socklist *psl;
> +   int fmode;
> +
> +   fmode = __ip6_mc_msf_lookup(sk, group, gf_interface, &psl);
> +   if (fmode < 0)
> +      return fmode;
> +
> +   if (psl) {
> +      int count = psl ? psl->sl_count : 0;
> +      int i, copycount;
> +      struct sockaddr_in6 sin6;
> +
> +      copycount = count < gf_numsrc ? count : gf_numsrc;
> +
> +      if (put_user(COMPAT_GROUP_FILTER_SIZE(copycount), optlen) ||
> +          access_ok(VERIFY_WRITE, optval, 
COMPAT_GROUP_FILTER_SIZE(copycount)) ||

        numsrc == 0 case works?

> +          __put_user((u32)fmode, &optval->gf_fmode) ||
> +          __put_user((u32)count, &optval->gf_numsrc))
> +         return -EFAULT;
> +
> +      /* changes to psl require the socket lock, a read lock on
> +       * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
> +       * have the socket lock, so reading here is safe.
> +       */
> +      memset(&sin6, 0, sizeof(sin6));
> +      sin6.sin6_family = AF_INET6;
> +
> +      for (i = 0; i < copycount; i++) {
> +         struct sockaddr_in6 __user *usin6 = (void __user 
*)&optval->gf_slist[i];
> +
> +         ipv6_addr_copy(&sin6.sin6_addr, &psl->sl_addr[i]);
> +
> +         if (__copy_to_user(usin6, &sin6, sizeof(sin6)) ||
> +             __clear_user(usin6 + 1, sizeof(optval->gf_slist[i]) - 
sizeof(*usin6)))

why explicitly clear the rest of it?

...stopping here; will continue looking at the rest.

                                                +-DLS

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ