[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <OFAF2C4F7A.77CF5A8D-ON88257437.0001566B-88257437.00023C8D@us.ibm.com>
Date: Fri, 25 Apr 2008 18:24:28 -0600
From: David Stevens <dlstevens@...ibm.com>
To: YOSHIFUJI Hideaki / 吉藤英明
<yoshfuji@...ux-ipv6.org>, davem@...emloft.net
Cc: netdev@...r.kernel.org, yoshfuji@...ux-ipv6.org
Subject: Re: [GIT PULL] [IPV6] COMPAT: Fix SSM applications on 64bit kernels.
Here's what I have for setsockopt, v4 & v6 and tested with both.
I discovered that the aligned attribute is only a minimum, so
aligned by itself has no effect on padding. GNU documentation
says you need both aligned and packed to make the pad be
a certain value. In this case, because the items that
are padded are 32 bit, they are identical with and without on all
architectures, but I stuck in the aligned all the same.
Patch is against 2.6.18, but it applies to 2.6.25 too.
I'll get to work on getsockopt for these now.
+-DLS
Patch blurb:
Added 32-bit compatibility support for setsockopt using
MCAST_* socket options.
Signed-off-by: David L Stevens <dlstevens@...ibm.com>
diff -ruNp linux-2.6.18.ppc64/include/net/compat.h
linux-2.6.18.ppc64DLS1/include/net/compat.h
--- linux-2.6.18.ppc64/include/net/compat.h 2008-04-21
13:50:33.000000000 -0700
+++ linux-2.6.18.ppc64DLS1/include/net/compat.h 2008-04-25
03:13:39.000000000 -0700
@@ -39,4 +39,6 @@ extern int put_cmsg_compat(struct msghdr
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock
*, unsigned char *, int);
+extern int compat_mc_setsockopt(struct sock *, int, int, char __user *,
int);
+
#endif /* NET_COMPAT_H */
diff -ruNp linux-2.6.18.ppc64/net/compat.c
linux-2.6.18.ppc64DLS1/net/compat.c
--- linux-2.6.18.ppc64/net/compat.c 2008-04-21 13:51:02.000000000
-0700
+++ linux-2.6.18.ppc64DLS1/net/compat.c 2008-04-25 08:53:47.000000000
-0700
@@ -26,6 +26,8 @@
#include <net/scm.h>
#include <net/sock.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include <asm/uaccess.h>
#include <net/compat.h>
@@ -589,6 +591,122 @@ asmlinkage long compat_sys_getsockopt(in
}
return err;
}
+
+struct compat_group_req {
+ __u32 gr_interface;
+ struct __kernel_sockaddr_storage gr_group
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+struct compat_group_source_req {
+ __u32 gsr_interface;
+ struct __kernel_sockaddr_storage gsr_group
+ __attribute__ ((aligned(4)));
+ struct __kernel_sockaddr_storage gsr_source
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+struct compat_group_filter {
+ __u32 gf_interface;
+ struct __kernel_sockaddr_storage gf_group
+ __attribute__ ((aligned(4)));
+ __u32 gf_fmode;
+ __u32 gf_numsrc;
+ struct __kernel_sockaddr_storage gf_slist[1]
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+
+int compat_mc_setsockopt(struct sock *sock, int level, int optname,
+ char __user *optval, int optlen)
+{
+ char __user *koptval = optval;
+ int koptlen = optlen;
+
+ switch (optname) {
+ case MCAST_JOIN_GROUP:
+ case MCAST_LEAVE_GROUP:
+ {
+ struct compat_group_req __user *gr32 = (void *)optval;
+ struct group_req __user *kgr =
+ compat_alloc_user_space(sizeof(struct group_req));
+ u32 interface;
+
+ if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) ||
+ !access_ok(VERIFY_WRITE, kgr, sizeof(struct
group_req)) ||
+ __get_user(interface, &gr32->gr_interface) ||
+ __put_user(interface, &kgr->gr_interface) ||
+ copy_in_user(&kgr->gr_group, &gr32->gr_group,
+ sizeof(kgr->gr_group)))
+ return -EFAULT;
+ koptval = (char __user *)kgr;
+ koptlen = sizeof(struct group_req);
+ break;
+ }
+ case MCAST_JOIN_SOURCE_GROUP:
+ case MCAST_LEAVE_SOURCE_GROUP:
+ case MCAST_BLOCK_SOURCE:
+ case MCAST_UNBLOCK_SOURCE:
+ {
+ struct compat_group_source_req __user *gsr32 = (void
*)optval;
+ struct group_source_req *kgsr = compat_alloc_user_space(
+ sizeof(struct group_source_req));
+ u32 interface;
+
+ if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) ||
+ !access_ok(VERIFY_WRITE, kgsr,
+ sizeof(struct group_source_req)) ||
+ __get_user(interface, &gsr32->gsr_interface) ||
+ __put_user(interface, &kgsr->gsr_interface) ||
+ copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
+ sizeof(kgsr->gsr_group)) ||
+ copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
+ sizeof(kgsr->gsr_source)))
+ return -EFAULT;
+ koptval = (char __user *)kgsr;
+ koptlen = sizeof(struct group_source_req);
+ break;
+ }
+ case MCAST_MSFILTER:
+ {
+ struct compat_group_filter __user *gf32 = (void *)optval;
+ struct group_filter *kgf;
+ u32 interface, fmode, numsrc;
+
+ if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+ __get_user(interface, &gf32->gf_interface) ||
+ __get_user(fmode, &gf32->gf_fmode) ||
+ __get_user(numsrc, &gf32->gf_numsrc))
+ return -EFAULT;
+ koptlen = optlen + sizeof(struct group_filter) -
+ sizeof(struct compat_group_filter);
+ if (koptlen < GROUP_FILTER_SIZE(numsrc))
+ return -EINVAL;
+ kgf = compat_alloc_user_space(koptlen);
+ if (!access_ok(VERIFY_WRITE, kgf, koptlen) ||
+ __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)) ||
+ (numsrc && copy_in_user(&kgf->gf_slist,
&gf32->gf_slist,
+ numsrc * sizeof(kgf->gf_slist[0]))))
+ return -EFAULT;
+ koptval = (char __user *)kgf;
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (level == SOL_IPV6)
+ return ipv6_setsockopt(sock, level, optname, koptval,
koptlen);
+ return ip_setsockopt(sock, level, optname, koptval, koptlen);
+}
+
+EXPORT_SYMBOL(compat_mc_setsockopt);
+
+
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
diff -ruNp linux-2.6.18.ppc64/net/ipv4/ip_sockglue.c
linux-2.6.18.ppc64DLS1/net/ipv4/ip_sockglue.c
--- linux-2.6.18.ppc64/net/ipv4/ip_sockglue.c 2008-04-21
13:51:00.000000000 -0700
+++ linux-2.6.18.ppc64DLS1/net/ipv4/ip_sockglue.c 2008-04-25
08:16:40.000000000 -0700
@@ -37,6 +37,7 @@
#include <linux/mroute.h>
#include <net/route.h>
#include <net/xfrm.h>
+#include <net/compat.h>
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/transp_v6.h>
#endif
@@ -921,6 +922,9 @@ int compat_ip_setsockopt(struct sock *sk
if (level != SOL_IP)
return -ENOPROTOOPT;
+ if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
+ return compat_mc_setsockopt(sk, level, optname, optval,
optlen);
+
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default
case */
diff -ruNp linux-2.6.18.ppc64/net/ipv6/ipv6_sockglue.c
linux-2.6.18.ppc64DLS1/net/ipv6/ipv6_sockglue.c
--- linux-2.6.18.ppc64/net/ipv6/ipv6_sockglue.c 2008-04-21
13:51:02.000000000 -0700
+++ linux-2.6.18.ppc64DLS1/net/ipv6/ipv6_sockglue.c 2008-04-25
05:34:02.000000000 -0700
@@ -52,6 +52,7 @@
#include <net/tcp.h>
#include <net/udp.h>
#include <net/xfrm.h>
+#include <net/compat.h>
#include <asm/uaccess.h>
@@ -769,6 +770,9 @@ int compat_ipv6_setsockopt(struct sock *
if (level != SOL_IPV6)
return -ENOPROTOOPT;
+ if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
+ return compat_mc_setsockopt(sk, level, optname, optval,
optlen);
+
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default
case */
Download attachment "setsockopt2.patch" of type "application/octet-stream" (6486 bytes)
Powered by blists - more mailing lists