diff options
author | David S. Miller <davem@davemloft.net> | 2014-11-21 12:17:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-21 12:17:35 -0500 |
commit | 675a53bd689c217bbe2736c09a57e10f95c686a7 (patch) | |
tree | 9f4f3c1f4fac484e6994f88ea383d8af93be2bfd | |
parent | abd40774132b8dd474ee0ac1532df1af843ada59 (diff) | |
parent | 232365f660b0016dcf618723707f91f4a95013db (diff) |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
-rw-r--r-- | arch/arm/kernel/sys_oabi-compat.c | 4 | ||||
-rw-r--r-- | include/linux/socket.h | 17 | ||||
-rw-r--r-- | include/linux/syscalls.h | 6 | ||||
-rw-r--r-- | include/net/compat.h | 5 | ||||
-rw-r--r-- | include/net/sock.h | 23 | ||||
-rw-r--r-- | net/compat.c | 83 | ||||
-rw-r--r-- | net/core/iovec.c | 47 | ||||
-rw-r--r-- | net/socket.c | 140 |
8 files changed, 114 insertions, 211 deletions
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index e90a3148f385..b83f3b7737fb 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c | |||
@@ -400,7 +400,7 @@ asmlinkage long sys_oabi_sendto(int fd, void __user *buff, | |||
400 | return sys_sendto(fd, buff, len, flags, addr, addrlen); | 400 | return sys_sendto(fd, buff, len, flags, addr, addrlen); |
401 | } | 401 | } |
402 | 402 | ||
403 | asmlinkage long sys_oabi_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | 403 | asmlinkage long sys_oabi_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags) |
404 | { | 404 | { |
405 | struct sockaddr __user *addr; | 405 | struct sockaddr __user *addr; |
406 | int msg_namelen; | 406 | int msg_namelen; |
@@ -446,7 +446,7 @@ asmlinkage long sys_oabi_socketcall(int call, unsigned long __user *args) | |||
446 | break; | 446 | break; |
447 | case SYS_SENDMSG: | 447 | case SYS_SENDMSG: |
448 | if (copy_from_user(a, args, 3 * sizeof(long)) == 0) | 448 | if (copy_from_user(a, args, 3 * sizeof(long)) == 0) |
449 | r = sys_oabi_sendmsg(a[0], (struct msghdr __user *)a[1], a[2]); | 449 | r = sys_oabi_sendmsg(a[0], (struct user_msghdr __user *)a[1], a[2]); |
450 | break; | 450 | break; |
451 | default: | 451 | default: |
452 | r = sys_socketcall(call, args); | 452 | r = sys_socketcall(call, args); |
diff --git a/include/linux/socket.h b/include/linux/socket.h index bb9b83640070..de5222832be4 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -53,10 +53,20 @@ struct msghdr { | |||
53 | __kernel_size_t msg_controllen; /* ancillary data buffer length */ | 53 | __kernel_size_t msg_controllen; /* ancillary data buffer length */ |
54 | unsigned int msg_flags; /* flags on received message */ | 54 | unsigned int msg_flags; /* flags on received message */ |
55 | }; | 55 | }; |
56 | |||
57 | struct user_msghdr { | ||
58 | void __user *msg_name; /* ptr to socket address structure */ | ||
59 | int msg_namelen; /* size of socket address structure */ | ||
60 | struct iovec __user *msg_iov; /* scatter/gather array */ | ||
61 | __kernel_size_t msg_iovlen; /* # elements in msg_iov */ | ||
62 | void __user *msg_control; /* ancillary data */ | ||
63 | __kernel_size_t msg_controllen; /* ancillary data buffer length */ | ||
64 | unsigned int msg_flags; /* flags on received message */ | ||
65 | }; | ||
56 | 66 | ||
57 | /* For recvmmsg/sendmmsg */ | 67 | /* For recvmmsg/sendmmsg */ |
58 | struct mmsghdr { | 68 | struct mmsghdr { |
59 | struct msghdr msg_hdr; | 69 | struct user_msghdr msg_hdr; |
60 | unsigned int msg_len; | 70 | unsigned int msg_len; |
61 | }; | 71 | }; |
62 | 72 | ||
@@ -312,15 +322,14 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, | |||
312 | extern unsigned long iov_pages(const struct iovec *iov, int offset, | 322 | extern unsigned long iov_pages(const struct iovec *iov, int offset, |
313 | unsigned long nr_segs); | 323 | unsigned long nr_segs); |
314 | 324 | ||
315 | extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); | ||
316 | extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); | 325 | extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); |
317 | extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); | 326 | extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); |
318 | 327 | ||
319 | struct timespec; | 328 | struct timespec; |
320 | 329 | ||
321 | /* The __sys_...msg variants allow MSG_CMSG_COMPAT */ | 330 | /* The __sys_...msg variants allow MSG_CMSG_COMPAT */ |
322 | extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); | 331 | extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); |
323 | extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); | 332 | extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); |
324 | extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | 333 | extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, |
325 | unsigned int flags, struct timespec *timeout); | 334 | unsigned int flags, struct timespec *timeout); |
326 | extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, | 335 | extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index bda9b81357cc..c9afdc7a7f84 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -25,7 +25,7 @@ struct linux_dirent64; | |||
25 | struct list_head; | 25 | struct list_head; |
26 | struct mmap_arg_struct; | 26 | struct mmap_arg_struct; |
27 | struct msgbuf; | 27 | struct msgbuf; |
28 | struct msghdr; | 28 | struct user_msghdr; |
29 | struct mmsghdr; | 29 | struct mmsghdr; |
30 | struct msqid_ds; | 30 | struct msqid_ds; |
31 | struct new_utsname; | 31 | struct new_utsname; |
@@ -601,13 +601,13 @@ asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); | |||
601 | asmlinkage long sys_send(int, void __user *, size_t, unsigned); | 601 | asmlinkage long sys_send(int, void __user *, size_t, unsigned); |
602 | asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, | 602 | asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, |
603 | struct sockaddr __user *, int); | 603 | struct sockaddr __user *, int); |
604 | asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); | 604 | asmlinkage long sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); |
605 | asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, | 605 | asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, |
606 | unsigned int vlen, unsigned flags); | 606 | unsigned int vlen, unsigned flags); |
607 | asmlinkage long sys_recv(int, void __user *, size_t, unsigned); | 607 | asmlinkage long sys_recv(int, void __user *, size_t, unsigned); |
608 | asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, | 608 | asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, |
609 | struct sockaddr __user *, int __user *); | 609 | struct sockaddr __user *, int __user *); |
610 | asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); | 610 | asmlinkage long sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); |
611 | asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, | 611 | asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, |
612 | unsigned int vlen, unsigned flags, | 612 | unsigned int vlen, unsigned flags, |
613 | struct timespec __user *timeout); | 613 | struct timespec __user *timeout); |
diff --git a/include/net/compat.h b/include/net/compat.h index 3b603b199c01..42a9c8431177 100644 --- a/include/net/compat.h +++ b/include/net/compat.h | |||
@@ -40,9 +40,8 @@ int compat_sock_get_timestampns(struct sock *, struct timespec __user *); | |||
40 | #define compat_mmsghdr mmsghdr | 40 | #define compat_mmsghdr mmsghdr |
41 | #endif /* defined(CONFIG_COMPAT) */ | 41 | #endif /* defined(CONFIG_COMPAT) */ |
42 | 42 | ||
43 | int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); | 43 | ssize_t get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, |
44 | int verify_compat_iovec(struct msghdr *, struct iovec *, | 44 | struct sockaddr __user **, struct iovec **); |
45 | struct sockaddr_storage *, int); | ||
46 | asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, | 45 | asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, |
47 | unsigned int); | 46 | unsigned int); |
48 | asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, | 47 | asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, |
diff --git a/include/net/sock.h b/include/net/sock.h index 83a669f83bae..df9b89bce8ff 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -1884,29 +1884,6 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, | |||
1884 | return 0; | 1884 | return 0; |
1885 | } | 1885 | } |
1886 | 1886 | ||
1887 | static inline int skb_copy_to_page(struct sock *sk, char __user *from, | ||
1888 | struct sk_buff *skb, struct page *page, | ||
1889 | int off, int copy) | ||
1890 | { | ||
1891 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
1892 | int err = 0; | ||
1893 | __wsum csum = csum_and_copy_from_user(from, | ||
1894 | page_address(page) + off, | ||
1895 | copy, 0, &err); | ||
1896 | if (err) | ||
1897 | return err; | ||
1898 | skb->csum = csum_block_add(skb->csum, csum, skb->len); | ||
1899 | } else if (copy_from_user(page_address(page) + off, from, copy)) | ||
1900 | return -EFAULT; | ||
1901 | |||
1902 | skb->len += copy; | ||
1903 | skb->data_len += copy; | ||
1904 | skb->truesize += copy; | ||
1905 | sk->sk_wmem_queued += copy; | ||
1906 | sk_mem_charge(sk, copy); | ||
1907 | return 0; | ||
1908 | } | ||
1909 | |||
1910 | /** | 1887 | /** |
1911 | * sk_wmem_alloc_get - returns write allocations | 1888 | * sk_wmem_alloc_get - returns write allocations |
1912 | * @sk: socket | 1889 | * @sk: socket |
diff --git a/net/compat.c b/net/compat.c index bc8aeefddf3f..062f157d2a6b 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -31,41 +31,18 @@ | |||
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <net/compat.h> | 32 | #include <net/compat.h> |
33 | 33 | ||
34 | static inline int iov_from_user_compat_to_kern(struct iovec *kiov, | 34 | ssize_t get_compat_msghdr(struct msghdr *kmsg, |
35 | struct compat_iovec __user *uiov32, | 35 | struct compat_msghdr __user *umsg, |
36 | int niov) | 36 | struct sockaddr __user **save_addr, |
37 | struct iovec **iov) | ||
37 | { | 38 | { |
38 | int tot_len = 0; | 39 | compat_uptr_t uaddr, uiov, tmp3; |
39 | 40 | ssize_t err; | |
40 | while (niov > 0) { | ||
41 | compat_uptr_t buf; | ||
42 | compat_size_t len; | ||
43 | |||
44 | if (get_user(len, &uiov32->iov_len) || | ||
45 | get_user(buf, &uiov32->iov_base)) | ||
46 | return -EFAULT; | ||
47 | |||
48 | if (len > INT_MAX - tot_len) | ||
49 | len = INT_MAX - tot_len; | ||
50 | |||
51 | tot_len += len; | ||
52 | kiov->iov_base = compat_ptr(buf); | ||
53 | kiov->iov_len = (__kernel_size_t) len; | ||
54 | uiov32++; | ||
55 | kiov++; | ||
56 | niov--; | ||
57 | } | ||
58 | return tot_len; | ||
59 | } | ||
60 | |||
61 | int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) | ||
62 | { | ||
63 | compat_uptr_t tmp1, tmp2, tmp3; | ||
64 | 41 | ||
65 | if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || | 42 | if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || |
66 | __get_user(tmp1, &umsg->msg_name) || | 43 | __get_user(uaddr, &umsg->msg_name) || |
67 | __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || | 44 | __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || |
68 | __get_user(tmp2, &umsg->msg_iov) || | 45 | __get_user(uiov, &umsg->msg_iov) || |
69 | __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || | 46 | __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || |
70 | __get_user(tmp3, &umsg->msg_control) || | 47 | __get_user(tmp3, &umsg->msg_control) || |
71 | __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || | 48 | __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || |
@@ -73,39 +50,33 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) | |||
73 | return -EFAULT; | 50 | return -EFAULT; |
74 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) | 51 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) |
75 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); | 52 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); |
76 | kmsg->msg_name = compat_ptr(tmp1); | ||
77 | kmsg->msg_iov = compat_ptr(tmp2); | ||
78 | kmsg->msg_control = compat_ptr(tmp3); | 53 | kmsg->msg_control = compat_ptr(tmp3); |
79 | return 0; | ||
80 | } | ||
81 | 54 | ||
82 | /* I've named the args so it is easy to tell whose space the pointers are in. */ | 55 | if (save_addr) |
83 | int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, | 56 | *save_addr = compat_ptr(uaddr); |
84 | struct sockaddr_storage *kern_address, int mode) | ||
85 | { | ||
86 | int tot_len; | ||
87 | 57 | ||
88 | if (kern_msg->msg_name && kern_msg->msg_namelen) { | 58 | if (uaddr && kmsg->msg_namelen) { |
89 | if (mode == VERIFY_READ) { | 59 | if (!save_addr) { |
90 | int err = move_addr_to_kernel(kern_msg->msg_name, | 60 | err = move_addr_to_kernel(compat_ptr(uaddr), |
91 | kern_msg->msg_namelen, | 61 | kmsg->msg_namelen, |
92 | kern_address); | 62 | kmsg->msg_name); |
93 | if (err < 0) | 63 | if (err < 0) |
94 | return err; | 64 | return err; |
95 | } | 65 | } |
96 | kern_msg->msg_name = kern_address; | ||
97 | } else { | 66 | } else { |
98 | kern_msg->msg_name = NULL; | 67 | kmsg->msg_name = NULL; |
99 | kern_msg->msg_namelen = 0; | 68 | kmsg->msg_namelen = 0; |
100 | } | 69 | } |
101 | 70 | ||
102 | tot_len = iov_from_user_compat_to_kern(kern_iov, | 71 | if (kmsg->msg_iovlen > UIO_MAXIOV) |
103 | (struct compat_iovec __user *)kern_msg->msg_iov, | 72 | return -EMSGSIZE; |
104 | kern_msg->msg_iovlen); | ||
105 | if (tot_len >= 0) | ||
106 | kern_msg->msg_iov = kern_iov; | ||
107 | 73 | ||
108 | return tot_len; | 74 | err = compat_rw_copy_check_uvector(save_addr ? READ : WRITE, |
75 | compat_ptr(uiov), kmsg->msg_iovlen, | ||
76 | UIO_FASTIOV, *iov, iov); | ||
77 | if (err >= 0) | ||
78 | kmsg->msg_iov = *iov; | ||
79 | return err; | ||
109 | } | 80 | } |
110 | 81 | ||
111 | /* Bleech... */ | 82 | /* Bleech... */ |
@@ -740,7 +711,7 @@ COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, uns | |||
740 | { | 711 | { |
741 | if (flags & MSG_CMSG_COMPAT) | 712 | if (flags & MSG_CMSG_COMPAT) |
742 | return -EINVAL; | 713 | return -EINVAL; |
743 | return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); | 714 | return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT); |
744 | } | 715 | } |
745 | 716 | ||
746 | COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, | 717 | COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, |
@@ -756,7 +727,7 @@ COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, uns | |||
756 | { | 727 | { |
757 | if (flags & MSG_CMSG_COMPAT) | 728 | if (flags & MSG_CMSG_COMPAT) |
758 | return -EINVAL; | 729 | return -EINVAL; |
759 | return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); | 730 | return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT); |
760 | } | 731 | } |
761 | 732 | ||
762 | COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags) | 733 | COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags) |
diff --git a/net/core/iovec.c b/net/core/iovec.c index e1ec45ab1e63..dcbe98b3726a 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c | |||
@@ -28,53 +28,6 @@ | |||
28 | #include <net/sock.h> | 28 | #include <net/sock.h> |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Verify iovec. The caller must ensure that the iovec is big enough | ||
32 | * to hold the message iovec. | ||
33 | * | ||
34 | * Save time not doing access_ok. copy_*_user will make this work | ||
35 | * in any case. | ||
36 | */ | ||
37 | |||
38 | int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode) | ||
39 | { | ||
40 | int size, ct, err; | ||
41 | |||
42 | if (m->msg_name && m->msg_namelen) { | ||
43 | if (mode == VERIFY_READ) { | ||
44 | void __user *namep; | ||
45 | namep = (void __user __force *) m->msg_name; | ||
46 | err = move_addr_to_kernel(namep, m->msg_namelen, | ||
47 | address); | ||
48 | if (err < 0) | ||
49 | return err; | ||
50 | } | ||
51 | m->msg_name = address; | ||
52 | } else { | ||
53 | m->msg_name = NULL; | ||
54 | m->msg_namelen = 0; | ||
55 | } | ||
56 | |||
57 | size = m->msg_iovlen * sizeof(struct iovec); | ||
58 | if (copy_from_user(iov, (void __user __force *) m->msg_iov, size)) | ||
59 | return -EFAULT; | ||
60 | |||
61 | m->msg_iov = iov; | ||
62 | err = 0; | ||
63 | |||
64 | for (ct = 0; ct < m->msg_iovlen; ct++) { | ||
65 | size_t len = iov[ct].iov_len; | ||
66 | |||
67 | if (len > INT_MAX - err) { | ||
68 | len = INT_MAX - err; | ||
69 | iov[ct].iov_len = len; | ||
70 | } | ||
71 | err += len; | ||
72 | } | ||
73 | |||
74 | return err; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * And now for the all-in-one: copy and checksum from a user iovec | 31 | * And now for the all-in-one: copy and checksum from a user iovec |
79 | * directly to a datagram | 32 | * directly to a datagram |
80 | * Calls to csum_partial but the last must be in 32 bit chunks | 33 | * Calls to csum_partial but the last must be in 32 bit chunks |
diff --git a/net/socket.c b/net/socket.c index fe20c319a0bb..ee3ee39eefa5 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1988,13 +1988,26 @@ struct used_address { | |||
1988 | unsigned int name_len; | 1988 | unsigned int name_len; |
1989 | }; | 1989 | }; |
1990 | 1990 | ||
1991 | static int copy_msghdr_from_user(struct msghdr *kmsg, | 1991 | static ssize_t copy_msghdr_from_user(struct msghdr *kmsg, |
1992 | struct msghdr __user *umsg) | 1992 | struct user_msghdr __user *umsg, |
1993 | struct sockaddr __user **save_addr, | ||
1994 | struct iovec **iov) | ||
1993 | { | 1995 | { |
1994 | if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) | 1996 | struct sockaddr __user *uaddr; |
1997 | struct iovec __user *uiov; | ||
1998 | ssize_t err; | ||
1999 | |||
2000 | if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || | ||
2001 | __get_user(uaddr, &umsg->msg_name) || | ||
2002 | __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || | ||
2003 | __get_user(uiov, &umsg->msg_iov) || | ||
2004 | __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) || | ||
2005 | __get_user(kmsg->msg_control, &umsg->msg_control) || | ||
2006 | __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || | ||
2007 | __get_user(kmsg->msg_flags, &umsg->msg_flags)) | ||
1995 | return -EFAULT; | 2008 | return -EFAULT; |
1996 | 2009 | ||
1997 | if (kmsg->msg_name == NULL) | 2010 | if (!uaddr) |
1998 | kmsg->msg_namelen = 0; | 2011 | kmsg->msg_namelen = 0; |
1999 | 2012 | ||
2000 | if (kmsg->msg_namelen < 0) | 2013 | if (kmsg->msg_namelen < 0) |
@@ -2002,10 +2015,34 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, | |||
2002 | 2015 | ||
2003 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) | 2016 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) |
2004 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); | 2017 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); |
2005 | return 0; | 2018 | |
2019 | if (save_addr) | ||
2020 | *save_addr = uaddr; | ||
2021 | |||
2022 | if (uaddr && kmsg->msg_namelen) { | ||
2023 | if (!save_addr) { | ||
2024 | err = move_addr_to_kernel(uaddr, kmsg->msg_namelen, | ||
2025 | kmsg->msg_name); | ||
2026 | if (err < 0) | ||
2027 | return err; | ||
2028 | } | ||
2029 | } else { | ||
2030 | kmsg->msg_name = NULL; | ||
2031 | kmsg->msg_namelen = 0; | ||
2032 | } | ||
2033 | |||
2034 | if (kmsg->msg_iovlen > UIO_MAXIOV) | ||
2035 | return -EMSGSIZE; | ||
2036 | |||
2037 | err = rw_copy_check_uvector(save_addr ? READ : WRITE, | ||
2038 | uiov, kmsg->msg_iovlen, | ||
2039 | UIO_FASTIOV, *iov, iov); | ||
2040 | if (err >= 0) | ||
2041 | kmsg->msg_iov = *iov; | ||
2042 | return err; | ||
2006 | } | 2043 | } |
2007 | 2044 | ||
2008 | static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, | 2045 | static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, |
2009 | struct msghdr *msg_sys, unsigned int flags, | 2046 | struct msghdr *msg_sys, unsigned int flags, |
2010 | struct used_address *used_address) | 2047 | struct used_address *used_address) |
2011 | { | 2048 | { |
@@ -2017,34 +2054,15 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, | |||
2017 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); | 2054 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); |
2018 | /* 20 is size of ipv6_pktinfo */ | 2055 | /* 20 is size of ipv6_pktinfo */ |
2019 | unsigned char *ctl_buf = ctl; | 2056 | unsigned char *ctl_buf = ctl; |
2020 | int err, ctl_len, total_len; | 2057 | int ctl_len, total_len; |
2021 | 2058 | ssize_t err; | |
2022 | err = -EFAULT; | ||
2023 | if (MSG_CMSG_COMPAT & flags) { | ||
2024 | if (get_compat_msghdr(msg_sys, msg_compat)) | ||
2025 | return -EFAULT; | ||
2026 | } else { | ||
2027 | err = copy_msghdr_from_user(msg_sys, msg); | ||
2028 | if (err) | ||
2029 | return err; | ||
2030 | } | ||
2031 | 2059 | ||
2032 | if (msg_sys->msg_iovlen > UIO_FASTIOV) { | 2060 | msg_sys->msg_name = &address; |
2033 | err = -EMSGSIZE; | ||
2034 | if (msg_sys->msg_iovlen > UIO_MAXIOV) | ||
2035 | goto out; | ||
2036 | err = -ENOMEM; | ||
2037 | iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), | ||
2038 | GFP_KERNEL); | ||
2039 | if (!iov) | ||
2040 | goto out; | ||
2041 | } | ||
2042 | 2061 | ||
2043 | /* This will also move the address data into kernel space */ | 2062 | if (MSG_CMSG_COMPAT & flags) |
2044 | if (MSG_CMSG_COMPAT & flags) { | 2063 | err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov); |
2045 | err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); | 2064 | else |
2046 | } else | 2065 | err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov); |
2047 | err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); | ||
2048 | if (err < 0) | 2066 | if (err < 0) |
2049 | goto out_freeiov; | 2067 | goto out_freeiov; |
2050 | total_len = err; | 2068 | total_len = err; |
@@ -2115,7 +2133,6 @@ out_freectl: | |||
2115 | out_freeiov: | 2133 | out_freeiov: |
2116 | if (iov != iovstack) | 2134 | if (iov != iovstack) |
2117 | kfree(iov); | 2135 | kfree(iov); |
2118 | out: | ||
2119 | return err; | 2136 | return err; |
2120 | } | 2137 | } |
2121 | 2138 | ||
@@ -2123,7 +2140,7 @@ out: | |||
2123 | * BSD sendmsg interface | 2140 | * BSD sendmsg interface |
2124 | */ | 2141 | */ |
2125 | 2142 | ||
2126 | long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | 2143 | long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags) |
2127 | { | 2144 | { |
2128 | int fput_needed, err; | 2145 | int fput_needed, err; |
2129 | struct msghdr msg_sys; | 2146 | struct msghdr msg_sys; |
@@ -2140,7 +2157,7 @@ out: | |||
2140 | return err; | 2157 | return err; |
2141 | } | 2158 | } |
2142 | 2159 | ||
2143 | SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) | 2160 | SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) |
2144 | { | 2161 | { |
2145 | if (flags & MSG_CMSG_COMPAT) | 2162 | if (flags & MSG_CMSG_COMPAT) |
2146 | return -EINVAL; | 2163 | return -EINVAL; |
@@ -2177,7 +2194,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2177 | 2194 | ||
2178 | while (datagrams < vlen) { | 2195 | while (datagrams < vlen) { |
2179 | if (MSG_CMSG_COMPAT & flags) { | 2196 | if (MSG_CMSG_COMPAT & flags) { |
2180 | err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, | 2197 | err = ___sys_sendmsg(sock, (struct user_msghdr __user *)compat_entry, |
2181 | &msg_sys, flags, &used_address); | 2198 | &msg_sys, flags, &used_address); |
2182 | if (err < 0) | 2199 | if (err < 0) |
2183 | break; | 2200 | break; |
@@ -2185,7 +2202,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2185 | ++compat_entry; | 2202 | ++compat_entry; |
2186 | } else { | 2203 | } else { |
2187 | err = ___sys_sendmsg(sock, | 2204 | err = ___sys_sendmsg(sock, |
2188 | (struct msghdr __user *)entry, | 2205 | (struct user_msghdr __user *)entry, |
2189 | &msg_sys, flags, &used_address); | 2206 | &msg_sys, flags, &used_address); |
2190 | if (err < 0) | 2207 | if (err < 0) |
2191 | break; | 2208 | break; |
@@ -2215,7 +2232,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, | |||
2215 | return __sys_sendmmsg(fd, mmsg, vlen, flags); | 2232 | return __sys_sendmmsg(fd, mmsg, vlen, flags); |
2216 | } | 2233 | } |
2217 | 2234 | ||
2218 | static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, | 2235 | static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, |
2219 | struct msghdr *msg_sys, unsigned int flags, int nosec) | 2236 | struct msghdr *msg_sys, unsigned int flags, int nosec) |
2220 | { | 2237 | { |
2221 | struct compat_msghdr __user *msg_compat = | 2238 | struct compat_msghdr __user *msg_compat = |
@@ -2223,44 +2240,22 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, | |||
2223 | struct iovec iovstack[UIO_FASTIOV]; | 2240 | struct iovec iovstack[UIO_FASTIOV]; |
2224 | struct iovec *iov = iovstack; | 2241 | struct iovec *iov = iovstack; |
2225 | unsigned long cmsg_ptr; | 2242 | unsigned long cmsg_ptr; |
2226 | int err, total_len, len; | 2243 | int total_len, len; |
2244 | ssize_t err; | ||
2227 | 2245 | ||
2228 | /* kernel mode address */ | 2246 | /* kernel mode address */ |
2229 | struct sockaddr_storage addr; | 2247 | struct sockaddr_storage addr; |
2230 | 2248 | ||
2231 | /* user mode address pointers */ | 2249 | /* user mode address pointers */ |
2232 | struct sockaddr __user *uaddr; | 2250 | struct sockaddr __user *uaddr; |
2233 | int __user *uaddr_len; | 2251 | int __user *uaddr_len = COMPAT_NAMELEN(msg); |
2234 | 2252 | ||
2235 | if (MSG_CMSG_COMPAT & flags) { | 2253 | msg_sys->msg_name = &addr; |
2236 | if (get_compat_msghdr(msg_sys, msg_compat)) | ||
2237 | return -EFAULT; | ||
2238 | } else { | ||
2239 | err = copy_msghdr_from_user(msg_sys, msg); | ||
2240 | if (err) | ||
2241 | return err; | ||
2242 | } | ||
2243 | |||
2244 | if (msg_sys->msg_iovlen > UIO_FASTIOV) { | ||
2245 | err = -EMSGSIZE; | ||
2246 | if (msg_sys->msg_iovlen > UIO_MAXIOV) | ||
2247 | goto out; | ||
2248 | err = -ENOMEM; | ||
2249 | iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), | ||
2250 | GFP_KERNEL); | ||
2251 | if (!iov) | ||
2252 | goto out; | ||
2253 | } | ||
2254 | 2254 | ||
2255 | /* Save the user-mode address (verify_iovec will change the | ||
2256 | * kernel msghdr to use the kernel address space) | ||
2257 | */ | ||
2258 | uaddr = (__force void __user *)msg_sys->msg_name; | ||
2259 | uaddr_len = COMPAT_NAMELEN(msg); | ||
2260 | if (MSG_CMSG_COMPAT & flags) | 2255 | if (MSG_CMSG_COMPAT & flags) |
2261 | err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); | 2256 | err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov); |
2262 | else | 2257 | else |
2263 | err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); | 2258 | err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov); |
2264 | if (err < 0) | 2259 | if (err < 0) |
2265 | goto out_freeiov; | 2260 | goto out_freeiov; |
2266 | total_len = err; | 2261 | total_len = err; |
@@ -2303,7 +2298,6 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, | |||
2303 | out_freeiov: | 2298 | out_freeiov: |
2304 | if (iov != iovstack) | 2299 | if (iov != iovstack) |
2305 | kfree(iov); | 2300 | kfree(iov); |
2306 | out: | ||
2307 | return err; | 2301 | return err; |
2308 | } | 2302 | } |
2309 | 2303 | ||
@@ -2311,7 +2305,7 @@ out: | |||
2311 | * BSD recvmsg interface | 2305 | * BSD recvmsg interface |
2312 | */ | 2306 | */ |
2313 | 2307 | ||
2314 | long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags) | 2308 | long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags) |
2315 | { | 2309 | { |
2316 | int fput_needed, err; | 2310 | int fput_needed, err; |
2317 | struct msghdr msg_sys; | 2311 | struct msghdr msg_sys; |
@@ -2328,7 +2322,7 @@ out: | |||
2328 | return err; | 2322 | return err; |
2329 | } | 2323 | } |
2330 | 2324 | ||
2331 | SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, | 2325 | SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, |
2332 | unsigned int, flags) | 2326 | unsigned int, flags) |
2333 | { | 2327 | { |
2334 | if (flags & MSG_CMSG_COMPAT) | 2328 | if (flags & MSG_CMSG_COMPAT) |
@@ -2373,7 +2367,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2373 | * No need to ask LSM for more than the first datagram. | 2367 | * No need to ask LSM for more than the first datagram. |
2374 | */ | 2368 | */ |
2375 | if (MSG_CMSG_COMPAT & flags) { | 2369 | if (MSG_CMSG_COMPAT & flags) { |
2376 | err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, | 2370 | err = ___sys_recvmsg(sock, (struct user_msghdr __user *)compat_entry, |
2377 | &msg_sys, flags & ~MSG_WAITFORONE, | 2371 | &msg_sys, flags & ~MSG_WAITFORONE, |
2378 | datagrams); | 2372 | datagrams); |
2379 | if (err < 0) | 2373 | if (err < 0) |
@@ -2382,7 +2376,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2382 | ++compat_entry; | 2376 | ++compat_entry; |
2383 | } else { | 2377 | } else { |
2384 | err = ___sys_recvmsg(sock, | 2378 | err = ___sys_recvmsg(sock, |
2385 | (struct msghdr __user *)entry, | 2379 | (struct user_msghdr __user *)entry, |
2386 | &msg_sys, flags & ~MSG_WAITFORONE, | 2380 | &msg_sys, flags & ~MSG_WAITFORONE, |
2387 | datagrams); | 2381 | datagrams); |
2388 | if (err < 0) | 2382 | if (err < 0) |
@@ -2571,13 +2565,13 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) | |||
2571 | (int __user *)a[4]); | 2565 | (int __user *)a[4]); |
2572 | break; | 2566 | break; |
2573 | case SYS_SENDMSG: | 2567 | case SYS_SENDMSG: |
2574 | err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); | 2568 | err = sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2]); |
2575 | break; | 2569 | break; |
2576 | case SYS_SENDMMSG: | 2570 | case SYS_SENDMMSG: |
2577 | err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); | 2571 | err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); |
2578 | break; | 2572 | break; |
2579 | case SYS_RECVMSG: | 2573 | case SYS_RECVMSG: |
2580 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); | 2574 | err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]); |
2581 | break; | 2575 | break; |
2582 | case SYS_RECVMMSG: | 2576 | case SYS_RECVMMSG: |
2583 | err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], | 2577 | err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], |