diff options
Diffstat (limited to 'net/compat.c')
| -rw-r--r-- | net/compat.c | 36 | 
1 files changed, 24 insertions, 12 deletions
diff --git a/net/compat.c b/net/compat.c index 1cd2ec046164..aba929e5250f 100644 --- a/net/compat.c +++ b/net/compat.c @@ -22,13 +22,14 @@  #include <linux/filter.h>  #include <linux/compat.h>  #include <linux/security.h> +#include <linux/audit.h>  #include <linux/export.h>  #include <net/scm.h>  #include <net/sock.h>  #include <net/ip.h>  #include <net/ipv6.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include <net/compat.h>  int get_compat_msghdr(struct msghdr *kmsg, @@ -90,11 +91,11 @@ int get_compat_msghdr(struct msghdr *kmsg,  #define CMSG_COMPAT_ALIGN(len)	ALIGN((len), sizeof(s32))  #define CMSG_COMPAT_DATA(cmsg)				\ -	((void __user *)((char __user *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)))) +	((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr)))  #define CMSG_COMPAT_SPACE(len)				\ -	(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len)) +	(sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len))  #define CMSG_COMPAT_LEN(len)				\ -	(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len)) +	(sizeof(struct compat_cmsghdr) + (len))  #define CMSG_COMPAT_FIRSTHDR(msg)			\  	(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ?	\ @@ -130,6 +131,9 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,  	__kernel_size_t kcmlen, tmp;  	int err = -EFAULT; +	BUILD_BUG_ON(sizeof(struct compat_cmsghdr) != +		     CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))); +  	kcmlen = 0;  	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); @@ -141,8 +145,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))  			return -EINVAL; -		tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + -		       CMSG_ALIGN(sizeof(struct cmsghdr))); +		tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));  		tmp = CMSG_ALIGN(tmp);  		kcmlen += tmp;  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); @@ -168,8 +171,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,  			goto Efault;  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))  			goto Einval; -		tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + -		       CMSG_ALIGN(sizeof(struct cmsghdr))); +		tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));  		if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))  			goto Einval;  		kcmsg->cmsg_len = tmp; @@ -178,7 +180,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,  		    __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||  		    copy_from_user(CMSG_DATA(kcmsg),  				   CMSG_COMPAT_DATA(ucmsg), -				   (ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))))) +				   (ucmlen - sizeof(*ucmsg))))  			goto Efault;  		/* Advance. */ @@ -781,14 +783,24 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,  COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)  { -	int ret; -	u32 a[6]; +	u32 a[AUDITSC_ARGS]; +	unsigned int len;  	u32 a0, a1; +	int ret;  	if (call < SYS_SOCKET || call > SYS_SENDMMSG)  		return -EINVAL; -	if (copy_from_user(a, args, nas[call])) +	len = nas[call]; +	if (len > sizeof(a)) +		return -EINVAL; + +	if (copy_from_user(a, args, len))  		return -EFAULT; + +	ret = audit_socketcall_compat(len / sizeof(a[0]), a); +	if (ret) +		return ret; +  	a0 = a[0];  	a1 = a[1];  | 
