forked from mirrors/linux
		
	net: Unbreak compat_sys_{send,recv}msg
I broke them in this commit:
    commit 1be374a051
    Author: Andy Lutomirski <luto@amacapital.net>
    Date:   Wed May 22 14:07:44 2013 -0700
        net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints.  It
also reverts some unnecessary checks in sys_socketcall.
Apparently I was suffering from underscore blindness the first time around.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Tested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									4d3797d7e1
								
							
						
					
					
						commit
						a7526eb5d0
					
				
					 3 changed files with 47 additions and 41 deletions
				
			
		| 
						 | 
					@ -320,6 +320,9 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct timespec;
 | 
					struct timespec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
 | 
				
			||||||
 | 
					extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
 | 
				
			||||||
 | 
					extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
 | 
				
			||||||
extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
					extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
				
			||||||
			  unsigned int flags, struct timespec *timeout);
 | 
								  unsigned int flags, struct timespec *timeout);
 | 
				
			||||||
extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
 | 
					extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								net/compat.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								net/compat.c
									
									
									
									
									
								
							| 
						 | 
					@ -734,19 +734,25 @@ static unsigned char nas[21] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
 | 
					asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
 | 
					asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
 | 
				
			||||||
				    unsigned int vlen, unsigned int flags)
 | 
									    unsigned int vlen, unsigned int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
	return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
						return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
				
			||||||
			      flags | MSG_CMSG_COMPAT);
 | 
								      flags | MSG_CMSG_COMPAT);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
 | 
					asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
 | 
					asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
 | 
				
			||||||
| 
						 | 
					@ -768,6 +774,9 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
 | 
				
			||||||
	int datagrams;
 | 
						int datagrams;
 | 
				
			||||||
	struct timespec ktspec;
 | 
						struct timespec ktspec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (COMPAT_USE_64BIT_TIME)
 | 
						if (COMPAT_USE_64BIT_TIME)
 | 
				
			||||||
		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
							return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
				
			||||||
				      flags | MSG_CMSG_COMPAT,
 | 
									      flags | MSG_CMSG_COMPAT,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										72
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								net/socket.c
									
									
									
									
									
								
							| 
						 | 
					@ -1956,7 +1956,7 @@ struct used_address {
 | 
				
			||||||
	unsigned int name_len;
 | 
						unsigned int name_len;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 | 
					static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 | 
				
			||||||
			 struct msghdr *msg_sys, unsigned int flags,
 | 
								 struct msghdr *msg_sys, unsigned int flags,
 | 
				
			||||||
			 struct used_address *used_address)
 | 
								 struct used_address *used_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2071,26 +2071,30 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 | 
				
			||||||
 *	BSD sendmsg interface
 | 
					 *	BSD sendmsg interface
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
 | 
					long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int fput_needed, err;
 | 
						int fput_needed, err;
 | 
				
			||||||
	struct msghdr msg_sys;
 | 
						struct msghdr msg_sys;
 | 
				
			||||||
	struct socket *sock;
 | 
						struct socket *sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & MSG_CMSG_COMPAT)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
						sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
				
			||||||
	if (!sock)
 | 
						if (!sock)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
 | 
						err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fput_light(sock->file, fput_needed);
 | 
						fput_light(sock->file, fput_needed);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return __sys_sendmsg(fd, msg, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	Linux sendmmsg interface
 | 
					 *	Linux sendmmsg interface
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -2121,15 +2125,16 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (datagrams < vlen) {
 | 
						while (datagrams < vlen) {
 | 
				
			||||||
		if (MSG_CMSG_COMPAT & flags) {
 | 
							if (MSG_CMSG_COMPAT & flags) {
 | 
				
			||||||
			err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
 | 
								err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
 | 
				
			||||||
					    &msg_sys, flags, &used_address);
 | 
										     &msg_sys, flags, &used_address);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			err = __put_user(err, &compat_entry->msg_len);
 | 
								err = __put_user(err, &compat_entry->msg_len);
 | 
				
			||||||
			++compat_entry;
 | 
								++compat_entry;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
 | 
								err = ___sys_sendmsg(sock,
 | 
				
			||||||
					    &msg_sys, flags, &used_address);
 | 
										     (struct msghdr __user *)entry,
 | 
				
			||||||
 | 
										     &msg_sys, flags, &used_address);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			err = put_user(err, &entry->msg_len);
 | 
								err = put_user(err, &entry->msg_len);
 | 
				
			||||||
| 
						 | 
					@ -2158,7 +2163,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
 | 
				
			||||||
	return __sys_sendmmsg(fd, mmsg, vlen, flags);
 | 
						return __sys_sendmmsg(fd, mmsg, vlen, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
 | 
					static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
 | 
				
			||||||
			 struct msghdr *msg_sys, unsigned int flags, int nosec)
 | 
								 struct msghdr *msg_sys, unsigned int flags, int nosec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct compat_msghdr __user *msg_compat =
 | 
						struct compat_msghdr __user *msg_compat =
 | 
				
			||||||
| 
						 | 
					@ -2250,27 +2255,31 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
 | 
				
			||||||
 *	BSD recvmsg interface
 | 
					 *	BSD recvmsg interface
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
 | 
					long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
 | 
				
			||||||
		unsigned int, flags)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int fput_needed, err;
 | 
						int fput_needed, err;
 | 
				
			||||||
	struct msghdr msg_sys;
 | 
						struct msghdr msg_sys;
 | 
				
			||||||
	struct socket *sock;
 | 
						struct socket *sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & MSG_CMSG_COMPAT)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
						sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
				
			||||||
	if (!sock)
 | 
						if (!sock)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
 | 
						err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fput_light(sock->file, fput_needed);
 | 
						fput_light(sock->file, fput_needed);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
 | 
				
			||||||
 | 
							unsigned int, flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (flags & MSG_CMSG_COMPAT)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return __sys_recvmsg(fd, msg, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *     Linux recvmmsg interface
 | 
					 *     Linux recvmmsg interface
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -2308,17 +2317,18 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
				
			||||||
		 * No need to ask LSM for more than the first datagram.
 | 
							 * No need to ask LSM for more than the first datagram.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (MSG_CMSG_COMPAT & flags) {
 | 
							if (MSG_CMSG_COMPAT & flags) {
 | 
				
			||||||
			err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
 | 
								err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
 | 
				
			||||||
					    &msg_sys, flags & ~MSG_WAITFORONE,
 | 
										     &msg_sys, flags & ~MSG_WAITFORONE,
 | 
				
			||||||
					    datagrams);
 | 
										     datagrams);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			err = __put_user(err, &compat_entry->msg_len);
 | 
								err = __put_user(err, &compat_entry->msg_len);
 | 
				
			||||||
			++compat_entry;
 | 
								++compat_entry;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
 | 
								err = ___sys_recvmsg(sock,
 | 
				
			||||||
					    &msg_sys, flags & ~MSG_WAITFORONE,
 | 
										     (struct msghdr __user *)entry,
 | 
				
			||||||
					    datagrams);
 | 
										     &msg_sys, flags & ~MSG_WAITFORONE,
 | 
				
			||||||
 | 
										     datagrams);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			err = put_user(err, &entry->msg_len);
 | 
								err = put_user(err, &entry->msg_len);
 | 
				
			||||||
| 
						 | 
					@ -2505,31 +2515,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
 | 
				
			||||||
				   (int __user *)a[4]);
 | 
									   (int __user *)a[4]);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SYS_SENDMSG:
 | 
						case SYS_SENDMSG:
 | 
				
			||||||
		if (a[2] & MSG_CMSG_COMPAT) {
 | 
					 | 
				
			||||||
			err = -EINVAL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
							err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SYS_SENDMMSG:
 | 
						case SYS_SENDMMSG:
 | 
				
			||||||
		if (a[3] & MSG_CMSG_COMPAT) {
 | 
					 | 
				
			||||||
			err = -EINVAL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
 | 
							err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SYS_RECVMSG:
 | 
						case SYS_RECVMSG:
 | 
				
			||||||
		if (a[2] & MSG_CMSG_COMPAT) {
 | 
					 | 
				
			||||||
			err = -EINVAL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
							err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SYS_RECVMMSG:
 | 
						case SYS_RECVMMSG:
 | 
				
			||||||
		if (a[3] & MSG_CMSG_COMPAT) {
 | 
					 | 
				
			||||||
			err = -EINVAL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
 | 
							err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
 | 
				
			||||||
				   (struct timespec __user *)a[4]);
 | 
									   (struct timespec __user *)a[4]);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue