Netdev List
 help / color / mirror / Atom feed
* [PATCH] add compat support for getsockopt (MCAST_MSFILTER)
@ 2008-04-28  5:41 David Stevens
  2008-04-28  6:36 ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 5+ messages in thread
From: David Stevens @ 2008-04-28  5:41 UTC (permalink / raw)
  To: davem, yoshfuji; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 8598 bytes --]

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. In addition, there are these cleanups
included for the setsockopt patch:

1) added missing "__user" for kgsr and kgf pointers
2) verify read for only GROUP_FILTER_SIZE(0). The group_filter
        structure definition (via RFC) includes space for one source
        in the source list array, but that source need not be present.
        So, sizeof(group_filter) > GROUP_FILTER_SIZE(0). Fixed
        the user read-check for minimum length to use the smaller size.
3) remove unneeded "&" for gf_slist addresses

[in-line for viewing, attached for applying]

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

diff -ruNp linux-2.6.18.ppc64DLS2/include/net/compat.h 
linux-2.6.18.ppc64GSO/include/net/compat.h
--- linux-2.6.18.ppc64DLS2/include/net/compat.h 2008-04-26 
04:34:04.000000000 -0700
+++ linux-2.6.18.ppc64GSO/include/net/compat.h  2008-04-27 
08:08:53.000000000 -0700
@@ -41,5 +41,8 @@ extern int cmsghdr_from_user_compat_to_k
 
 extern int compat_mc_setsockopt(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 */
diff -ruNp linux-2.6.18.ppc64DLS2/net/compat.c 
linux-2.6.18.ppc64GSO/net/compat.c
--- linux-2.6.18.ppc64DLS2/net/compat.c 2008-04-26 04:35:22.000000000 
-0700
+++ linux-2.6.18.ppc64GSO/net/compat.c  2008-04-27 13:55:40.000000000 
-0700
@@ -616,6 +616,9 @@ struct compat_group_filter {
                __attribute__ ((aligned(4)));
 } __attribute__ ((packed));
 
+#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
+                       sizeof(struct __kernel_sockaddr_storage))
+
 
 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
        char __user *optval, int optlen,
@@ -650,7 +653,7 @@ int compat_mc_setsockopt(struct sock *so
        case MCAST_UNBLOCK_SOURCE:
        {
                struct compat_group_source_req __user *gsr32 = (void 
*)optval;
-               struct group_source_req *kgsr = compat_alloc_user_space(
+               struct group_source_req __user *kgsr = 
compat_alloc_user_space(
                        sizeof(struct group_source_req));
                u32 interface;
 
@@ -671,10 +674,10 @@ int compat_mc_setsockopt(struct sock *so
        case MCAST_MSFILTER:
        {
                struct compat_group_filter __user *gf32 = (void *)optval;
-               struct group_filter *kgf;
+               struct group_filter __user *kgf;
                u32 interface, fmode, numsrc;
 
-               if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+               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))
@@ -690,7 +693,7 @@ int compat_mc_setsockopt(struct sock *so
                    __put_user(numsrc, &kgf->gf_numsrc) ||
                    copy_in_user(&kgf->gf_group, &gf32->gf_group,
                                sizeof(kgf->gf_group)) ||
-                   (numsrc && copy_in_user(&kgf->gf_slist, 
&gf32->gf_slist,
+                   (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
                                numsrc * sizeof(kgf->gf_slist[0]))))
                        return -EFAULT;
                koptval = (char __user *)kgf;
@@ -705,6 +708,85 @@ int compat_mc_setsockopt(struct sock *so
 
 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 */
 #define AL(x) ((x) * sizeof(u32))
diff -ruNp linux-2.6.18.ppc64DLS2/net/ipv4/ip_sockglue.c 
linux-2.6.18.ppc64GSO/net/ipv4/ip_sockglue.c
--- linux-2.6.18.ppc64DLS2/net/ipv4/ip_sockglue.c       2008-04-26 
04:36:24.000000000 -0700
+++ linux-2.6.18.ppc64GSO/net/ipv4/ip_sockglue.c        2008-04-27 
11:24:48.000000000 -0700
@@ -1193,7 +1193,14 @@ int ip_getsockopt(struct sock *sk, int l
 int compat_ip_getsockopt(struct sock *sk, int level, int optname,
                         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
        /* we need to exclude all possible ENOPROTOOPTs except default 
case */
        if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
diff -ruNp linux-2.6.18.ppc64DLS2/net/ipv6/ipv6_sockglue.c 
linux-2.6.18.ppc64GSO/net/ipv6/ipv6_sockglue.c
--- linux-2.6.18.ppc64DLS2/net/ipv6/ipv6_sockglue.c     2008-04-26 
04:35:19.000000000 -0700
+++ linux-2.6.18.ppc64GSO/net/ipv6/ipv6_sockglue.c      2008-04-27 
13:56:27.000000000 -0700
@@ -1062,6 +1062,10 @@ int compat_ipv6_getsockopt(struct sock *
        if (level != SOL_IPV6)
                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);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible EINVALs except default case */



[-- Attachment #2: getsockopt.patch --]
[-- Type: application/octet-stream, Size: 6722 bytes --]

diff -ruNp linux-2.6.18.ppc64DLS2/include/net/compat.h linux-2.6.18.ppc64GSO/include/net/compat.h
--- linux-2.6.18.ppc64DLS2/include/net/compat.h	2008-04-26 04:34:04.000000000 -0700
+++ linux-2.6.18.ppc64GSO/include/net/compat.h	2008-04-27 08:08:53.000000000 -0700
@@ -41,5 +41,8 @@ extern int cmsghdr_from_user_compat_to_k
 
 extern int compat_mc_setsockopt(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 */
diff -ruNp linux-2.6.18.ppc64DLS2/net/compat.c linux-2.6.18.ppc64GSO/net/compat.c
--- linux-2.6.18.ppc64DLS2/net/compat.c	2008-04-26 04:35:22.000000000 -0700
+++ linux-2.6.18.ppc64GSO/net/compat.c	2008-04-27 13:55:40.000000000 -0700
@@ -616,6 +616,9 @@ struct compat_group_filter {
 		__attribute__ ((aligned(4)));
 } __attribute__ ((packed));
 
+#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
+			sizeof(struct __kernel_sockaddr_storage))
+
 
 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
 	char __user *optval, int optlen,
@@ -650,7 +653,7 @@ int compat_mc_setsockopt(struct sock *so
 	case MCAST_UNBLOCK_SOURCE:
 	{
 		struct compat_group_source_req __user *gsr32 = (void *)optval;
-		struct group_source_req *kgsr = compat_alloc_user_space(
+		struct group_source_req __user *kgsr = compat_alloc_user_space(
 			sizeof(struct group_source_req));
 		u32 interface;
 
@@ -671,10 +674,10 @@ int compat_mc_setsockopt(struct sock *so
 	case MCAST_MSFILTER:
 	{
 		struct compat_group_filter __user *gf32 = (void *)optval;
-		struct group_filter *kgf;
+		struct group_filter __user *kgf;
 		u32 interface, fmode, numsrc;
 
-		if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+		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))
@@ -690,7 +693,7 @@ int compat_mc_setsockopt(struct sock *so
 		    __put_user(numsrc, &kgf->gf_numsrc) ||
 		    copy_in_user(&kgf->gf_group, &gf32->gf_group,
 				sizeof(kgf->gf_group)) ||
-		    (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist,
+		    (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
 				numsrc * sizeof(kgf->gf_slist[0]))))
 			return -EFAULT;
 		koptval = (char __user *)kgf;
@@ -705,6 +708,85 @@ int compat_mc_setsockopt(struct sock *so
 
 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 */
 #define AL(x) ((x) * sizeof(u32))
diff -ruNp linux-2.6.18.ppc64DLS2/net/ipv4/ip_sockglue.c linux-2.6.18.ppc64GSO/net/ipv4/ip_sockglue.c
--- linux-2.6.18.ppc64DLS2/net/ipv4/ip_sockglue.c	2008-04-26 04:36:24.000000000 -0700
+++ linux-2.6.18.ppc64GSO/net/ipv4/ip_sockglue.c	2008-04-27 11:24:48.000000000 -0700
@@ -1193,7 +1193,14 @@ int ip_getsockopt(struct sock *sk, int l
 int compat_ip_getsockopt(struct sock *sk, int level, int optname,
 			 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
 	/* we need to exclude all possible ENOPROTOOPTs except default case */
 	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
diff -ruNp linux-2.6.18.ppc64DLS2/net/ipv6/ipv6_sockglue.c linux-2.6.18.ppc64GSO/net/ipv6/ipv6_sockglue.c
--- linux-2.6.18.ppc64DLS2/net/ipv6/ipv6_sockglue.c	2008-04-26 04:35:19.000000000 -0700
+++ linux-2.6.18.ppc64GSO/net/ipv6/ipv6_sockglue.c	2008-04-27 13:56:27.000000000 -0700
@@ -1062,6 +1062,10 @@ int compat_ipv6_getsockopt(struct sock *
 	if (level != SOL_IPV6)
 		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);
 #ifdef CONFIG_NETFILTER
 	/* we need to exclude all possible EINVALs except default case */

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-04-29 10:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-28  5:41 [PATCH] add compat support for getsockopt (MCAST_MSFILTER) David Stevens
2008-04-28  6:36 ` YOSHIFUJI Hideaki / 吉藤英明
2008-04-28  6:54   ` David Stevens
2008-04-28  7:52     ` YOSHIFUJI Hideaki / 吉藤英明
2008-04-29 10:23       ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox