diff --git a/include/linux/socket.h b/include/linux/socket.h
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -90,6 +90,7 @@ struct cmsghdr {
 #define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
 
 #define CMSG_DATA(cmsg)	((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_DATA_USER(cmsg)	((void __user *)((char __user *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
 #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
 #define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
 
@@ -297,7 +298,15 @@ extern int verify_iovec(struct msghdr *m
 extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
 extern int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen);
 extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr);
-extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+extern int __put_cmsg(struct msghdr *msg, int level, int type,
+		      int len, void *data, struct cmsghdr __user *cm);
+
+static inline int put_cmsg(struct msghdr *msg, int level, int type,
+			   int len, void *data)
+{
+	return __put_cmsg(msg, level, type, len, data,
+			  (struct cmsghdr __user *)msg->msg_control);
+}
 
 #endif
 #endif /* not kernel and not glibc */
diff --git a/include/net/compat.h b/include/net/compat.h
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -32,7 +32,16 @@ extern int verify_compat_iovec(struct ms
 extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned);
 extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned);
 extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *);
-extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
+
+extern int __put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len,
+			     void *data, struct cmsghdr __user *kcm);
+static inline int put_cmsg_compat(struct msghdr *kmsg, int level, int type,
+				  int len, void *data)
+{
+	return __put_cmsg_compat(kmsg, level, type, len, data,
+				 (struct cmsghdr __user *)kmsg->msg_control);
+}
+
 extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, unsigned char *,
 		int);
 
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -30,9 +30,16 @@ extern int				udpv6_connect(struct sock 
 						      struct sockaddr *uaddr,
 						      int addr_len);
 
-extern int			datagram_recv_ctl(struct sock *sk,
-						  struct msghdr *msg,
-						  struct sk_buff *skb);
+extern int __datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+			       struct cmsghdr __user *cmsg,
+			       struct sk_buff *skb);
+extern inline int datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+				    struct sk_buff *skb)
+{
+	return __datagram_recv_ctl(sk, msg,
+				   (struct cmsghdr __user *)msg->msg_control,
+				   skb);
+}
 
 extern int			datagram_send_ctl(struct msghdr *msg,
 						  struct flowi *fl,
diff --git a/net/compat.c b/net/compat.c
--- a/net/compat.c
+++ b/net/compat.c
@@ -205,10 +205,11 @@ out_free_efault:
 	return -EFAULT;
 }
 
-int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
+int __put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len,
+		      void *data, struct cmsghdr __user *kcm)
 {
 	struct compat_timeval ctv;
-	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
+	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *)kcm;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
 
diff --git a/net/core/scm.c b/net/core/scm.c
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -164,15 +164,15 @@ error:
 	return err;
 }
 
-int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
+int __put_cmsg(struct msghdr * msg, int level, int type, int len, void *data,
+	       struct cmsghdr __user *cm)
 {
-	struct cmsghdr __user *cm = (struct cmsghdr __user *)msg->msg_control;
 	struct cmsghdr cmhdr;
 	int cmlen = CMSG_LEN(len);
 	int err;
 
 	if (MSG_CMSG_COMPAT & msg->msg_flags)
-		return put_cmsg_compat(msg, level, type, len, data);
+		return __put_cmsg_compat(msg, level, type, len, data, cm);
 
 	if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
 		msg->msg_flags |= MSG_CTRUNC;
@@ -189,7 +189,7 @@ int put_cmsg(struct msghdr * msg, int le
 	err = -EFAULT;
 	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
 		goto out; 
-	if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
+	if (copy_to_user(CMSG_DATA_USER(cm), data, cmlen - sizeof(struct cmsghdr)))
 		goto out;
 	cmlen = CMSG_SPACE(len);
 	msg->msg_control += cmlen;
@@ -221,7 +221,7 @@ void scm_detach_fds(struct msghdr *msg, 
 	if (fdnum < fdmax)
 		fdmax = fdnum;
 
-	for (i=0, cmfptr=(int __user *)CMSG_DATA(cm); i<fdmax; i++, cmfptr++)
+	for (i=0, cmfptr=(int __user *)CMSG_DATA_USER(cm); i<fdmax; i++, cmfptr++)
 	{
 		int new_fd;
 		err = security_file_receive(fp[i]);
@@ -285,6 +285,6 @@ struct scm_fp_list *scm_fp_dup(struct sc
 
 EXPORT_SYMBOL(__scm_destroy);
 EXPORT_SYMBOL(__scm_send);
-EXPORT_SYMBOL(put_cmsg);
+EXPORT_SYMBOL(__put_cmsg);
 EXPORT_SYMBOL(scm_detach_fds);
 EXPORT_SYMBOL(scm_fp_dup);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1032,7 +1032,6 @@ int ip_getsockopt(struct sock *sk, int l
 			if (sk->sk_type != SOCK_STREAM)
 				return -ENOPROTOOPT;
 
-			msg.msg_control = optval;
 			msg.msg_controllen = len;
 			msg.msg_flags = 0;
 
@@ -1042,11 +1041,15 @@ int ip_getsockopt(struct sock *sk, int l
 				info.ipi_addr.s_addr = inet->rcv_saddr;
 				info.ipi_spec_dst.s_addr = inet->rcv_saddr;
 				info.ipi_ifindex = inet->mc_index;
-				put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
+				__put_cmsg(&msg, SOL_IP, IP_PKTINFO,
+					   sizeof(info), &info,
+					   (struct cmsghdr __user *)optval);
 			}
 			if (inet->cmsg_flags & IP_CMSG_TTL) {
 				int hlim = inet->mc_ttl;
-				put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
+				__put_cmsg(&msg, SOL_IP, IP_TTL,
+					   sizeof(hlim), &hlim,
+					   (struct cmsghdr __user *)optval);
 			}
 			len -= msg.msg_controllen;
 			return put_user(len, optlen);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -370,9 +370,8 @@ out:
 	return err;
 }
 
-
-
-int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+int __datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+			struct cmsghdr __user *cmsg, struct sk_buff *skb)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct inet6_skb_parm *opt = IP6CB(skb);
@@ -382,33 +381,33 @@ int datagram_recv_ctl(struct sock *sk, s
 
 		src_info.ipi6_ifindex = opt->iif;
 		ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
-		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
+		__put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info, cmsg);
 	}
 
 	if (np->rxopt.bits.rxhlim) {
 		int hlim = skb->nh.ipv6h->hop_limit;
-		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
+		__put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim, cmsg);
 	}
 
 	if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
 		u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
-		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
+		__put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo, cmsg);
 	}
 	if (np->rxopt.bits.hopopts && opt->hop) {
 		u8 *ptr = skb->nh.raw + opt->hop;
-		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
+		__put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr, cmsg);
 	}
 	if (np->rxopt.bits.dstopts && opt->dst0) {
 		u8 *ptr = skb->nh.raw + opt->dst0;
-		put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+		__put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr, cmsg);
 	}
 	if (np->rxopt.bits.srcrt && opt->srcrt) {
 		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(skb->nh.raw + opt->srcrt);
-		put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
+		__put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, (rthdr->hdrlen+1) << 3, rthdr, cmsg);
 	}
 	if (np->rxopt.bits.dstopts && opt->dst1) {
 		u8 *ptr = skb->nh.raw + opt->dst1;
-		put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+		__put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr, cmsg);
 	}
 	return 0;
 }
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -571,11 +571,11 @@ int ipv6_getsockopt(struct sock *sk, int
 	{
 		struct msghdr msg;
 		struct sk_buff *skb;
+		struct cmsghdr __user *cmsg;
 
 		if (sk->sk_type != SOCK_STREAM)
 			return -ENOPROTOOPT;
 
-		msg.msg_control = optval;
 		msg.msg_controllen = len;
 		msg.msg_flags = 0;
 
@@ -585,8 +585,10 @@ int ipv6_getsockopt(struct sock *sk, int
 			atomic_inc(&skb->users);
 		release_sock(sk);
 
+		cmsg = (struct cmsghdr __user *)optval;
+
 		if (skb) {
-			int err = datagram_recv_ctl(sk, &msg, skb);
+			int err = __datagram_recv_ctl(sk, &msg, cmsg, skb);
 			kfree_skb(skb);
 			if (err)
 				return err;
@@ -595,11 +597,13 @@ int ipv6_getsockopt(struct sock *sk, int
 				struct in6_pktinfo src_info;
 				src_info.ipi6_ifindex = np->mcast_oif;
 				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
-				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
+				__put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO,
+					   sizeof(src_info), &src_info, cmsg);
 			}
 			if (np->rxopt.bits.rxhlim) {
 				int hlim = np->mcast_hops;
-				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
+				__put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT,
+					   sizeof(hlim), &hlim, cmsg);
 			}
 		}
 		len -= msg.msg_controllen;
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -1,12 +1,12 @@
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/netfilter_ipv6.h>
 
 #ifdef CONFIG_NETFILTER
 
 #include <linux/kernel.h>
 #include <linux/ipv6.h>
 #include <linux/netfilter.h>
-#include <linux/netfilter_ipv6.h>
 #include <net/dst.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>