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, | ||||
|  |  | |||
							
								
								
									
										72
									
								
								net/socket.c
									
										
									
									
									
								
							
							
						
						
									
										72
									
								
								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 @@ out: | |||
|  *	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,15 +2125,16 @@ 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, | ||||
| 					    &msg_sys, flags, &used_address); | ||||
| 			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, | ||||
| 					    &msg_sys, flags, &used_address); | ||||
| 			err = ___sys_sendmsg(sock, | ||||
| 					     (struct msghdr __user *)entry, | ||||
| 					     &msg_sys, flags, &used_address); | ||||
| 			if (err < 0) | ||||
| 				break; | ||||
| 			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); | ||||
| } | ||||
| 
 | ||||
| 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 @@ out: | |||
|  *	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,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. | ||||
| 		 */ | ||||
| 		if (MSG_CMSG_COMPAT & flags) { | ||||
| 			err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry, | ||||
| 					    &msg_sys, flags & ~MSG_WAITFORONE, | ||||
| 					    datagrams); | ||||
| 			err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, | ||||
| 					     &msg_sys, flags & ~MSG_WAITFORONE, | ||||
| 					     datagrams); | ||||
| 			if (err < 0) | ||||
| 				break; | ||||
| 			err = __put_user(err, &compat_entry->msg_len); | ||||
| 			++compat_entry; | ||||
| 		} else { | ||||
| 			err = __sys_recvmsg(sock, (struct msghdr __user *)entry, | ||||
| 					    &msg_sys, flags & ~MSG_WAITFORONE, | ||||
| 					    datagrams); | ||||
| 			err = ___sys_recvmsg(sock, | ||||
| 					     (struct msghdr __user *)entry, | ||||
| 					     &msg_sys, flags & ~MSG_WAITFORONE, | ||||
| 					     datagrams); | ||||
| 			if (err < 0) | ||||
| 				break; | ||||
| 			err = put_user(err, &entry->msg_len); | ||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andy Lutomirski
				Andy Lutomirski