mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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;
 | 
			
		||||
 | 
			
		||||
/* 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,
 | 
			
		||||
			  unsigned int flags, struct timespec *timeout);
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	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,
 | 
			
		||||
				    unsigned int vlen, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	if (flags & MSG_CMSG_COMPAT)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
			
		||||
			      flags | MSG_CMSG_COMPAT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			@ -768,6 +774,9 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
 | 
			
		|||
	int datagrams;
 | 
			
		||||
	struct timespec ktspec;
 | 
			
		||||
 | 
			
		||||
	if (flags & MSG_CMSG_COMPAT)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (COMPAT_USE_64BIT_TIME)
 | 
			
		||||
		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 | 
			
		||||
				      flags | MSG_CMSG_COMPAT,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								net/socket.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1956,7 +1956,7 @@ struct used_address {
 | 
			
		|||
	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 used_address *used_address)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2071,26 +2071,30 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 | 
			
		|||
 *	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;
 | 
			
		||||
	struct msghdr msg_sys;
 | 
			
		||||
	struct socket *sock;
 | 
			
		||||
 | 
			
		||||
	if (flags & MSG_CMSG_COMPAT)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
			
		||||
	if (!sock)
 | 
			
		||||
		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);
 | 
			
		||||
out:
 | 
			
		||||
	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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -2121,14 +2125,15 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
			
		|||
 | 
			
		||||
	while (datagrams < vlen) {
 | 
			
		||||
		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);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
				break;
 | 
			
		||||
			err = __put_user(err, &compat_entry->msg_len);
 | 
			
		||||
			++compat_entry;
 | 
			
		||||
		} else {
 | 
			
		||||
			err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
 | 
			
		||||
			err = ___sys_sendmsg(sock,
 | 
			
		||||
					     (struct msghdr __user *)entry,
 | 
			
		||||
					     &msg_sys, flags, &used_address);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
				break;
 | 
			
		||||
| 
						 | 
				
			
			@ -2158,7 +2163,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
 | 
			
		|||
	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 compat_msghdr __user *msg_compat =
 | 
			
		||||
| 
						 | 
				
			
			@ -2250,27 +2255,31 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
 | 
			
		|||
 *	BSD recvmsg interface
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
 | 
			
		||||
		unsigned int, flags)
 | 
			
		||||
long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
 | 
			
		||||
{
 | 
			
		||||
	int fput_needed, err;
 | 
			
		||||
	struct msghdr msg_sys;
 | 
			
		||||
	struct socket *sock;
 | 
			
		||||
 | 
			
		||||
	if (flags & MSG_CMSG_COMPAT)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 | 
			
		||||
	if (!sock)
 | 
			
		||||
		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);
 | 
			
		||||
out:
 | 
			
		||||
	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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -2308,7 +2317,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
			
		|||
		 * No need to ask LSM for more than the first datagram.
 | 
			
		||||
		 */
 | 
			
		||||
		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,
 | 
			
		||||
					     datagrams);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2316,7 +2325,8 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 | 
			
		|||
			err = __put_user(err, &compat_entry->msg_len);
 | 
			
		||||
			++compat_entry;
 | 
			
		||||
		} else {
 | 
			
		||||
			err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
 | 
			
		||||
			err = ___sys_recvmsg(sock,
 | 
			
		||||
					     (struct msghdr __user *)entry,
 | 
			
		||||
					     &msg_sys, flags & ~MSG_WAITFORONE,
 | 
			
		||||
					     datagrams);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2505,31 +2515,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
 | 
			
		|||
				   (int __user *)a[4]);
 | 
			
		||||
		break;
 | 
			
		||||
	case SYS_SENDMSG:
 | 
			
		||||
		if (a[2] & MSG_CMSG_COMPAT) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
			
		||||
		break;
 | 
			
		||||
	case SYS_SENDMMSG:
 | 
			
		||||
		if (a[3] & MSG_CMSG_COMPAT) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
 | 
			
		||||
		break;
 | 
			
		||||
	case SYS_RECVMSG:
 | 
			
		||||
		if (a[2] & MSG_CMSG_COMPAT) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
 | 
			
		||||
		break;
 | 
			
		||||
	case SYS_RECVMMSG:
 | 
			
		||||
		if (a[3] & MSG_CMSG_COMPAT) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
 | 
			
		||||
				   (struct timespec __user *)a[4]);
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue