aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-04-06 14:03:05 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-11-19 16:22:59 -0500
commit666547ff591cebdedc4679bf6b1b3f3383a8dea3 (patch)
tree59a5eadc4a3a1ca74ca7e6f36cb55f9808602368
parentdaaf427c6ab392bedcd018e326b2ffa1e1110cd6 (diff)
separate kernel- and userland-side msghdr
Kernel-side struct msghdr is (currently) using the same layout as userland one, but it's not a one-to-one copy - even without considering 32bit compat issues, we have msg_iov, msg_name and msg_control copied to kernel[1]. It's fairly localized, so we get away with a few functions where that knowledge is needed (and we could shrink that set even more). Pretty much everything deals with the kernel-side variant and the few places that want userland one just use a bunch of force-casts to paper over the differences. The thing is, kernel-side definition of struct msghdr is *not* exposed in include/uapi - libc doesn't see it, etc. So we can add struct user_msghdr, with proper annotations and let the few places that ever deal with those beasts use it for userland pointers. Saner typechecking aside, that will allow to change the layout of kernel-side msghdr - e.g. replace msg_iov/msg_iovlen there with struct iov_iter, getting rid of the need to modify the iovec as we copy data to/from it, etc. We could introduce kernel_msghdr instead, but that would create much more noise - the absolute majority of the instances would need to have the type switched to kernel_msghdr and definition of struct msghdr in include/linux/socket.h is not going to be seen by userland anyway. This commit just introduces user_msghdr and switches the few places that are dealing with userland-side msghdr to it. [1] actually, it's even trickier than that - we copy msg_control for sendmsg, but keep the userland address on recvmsg. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--arch/arm/kernel/sys_oabi-compat.c4
-rw-r--r--include/linux/socket.h16
-rw-r--r--include/linux/syscalls.h6
-rw-r--r--net/compat.c4
-rw-r--r--net/socket.c29
5 files changed, 36 insertions, 23 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
403asmlinkage long sys_oabi_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) 403asmlinkage 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..51bd6668b80e 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
57struct 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 */
58struct mmsghdr { 68struct 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
@@ -319,8 +329,8 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
319struct timespec; 329struct timespec;
320 330
321/* The __sys_...msg variants allow MSG_CMSG_COMPAT */ 331/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
322extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); 332extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
323extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); 333extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
324extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 334extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
325 unsigned int flags, struct timespec *timeout); 335 unsigned int flags, struct timespec *timeout);
326extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, 336extern 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;
25struct list_head; 25struct list_head;
26struct mmap_arg_struct; 26struct mmap_arg_struct;
27struct msgbuf; 27struct msgbuf;
28struct msghdr; 28struct user_msghdr;
29struct mmsghdr; 29struct mmsghdr;
30struct msqid_ds; 30struct msqid_ds;
31struct new_utsname; 31struct new_utsname;
@@ -601,13 +601,13 @@ asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *);
601asmlinkage long sys_send(int, void __user *, size_t, unsigned); 601asmlinkage long sys_send(int, void __user *, size_t, unsigned);
602asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, 602asmlinkage long sys_sendto(int, void __user *, size_t, unsigned,
603 struct sockaddr __user *, int); 603 struct sockaddr __user *, int);
604asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); 604asmlinkage long sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
605asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, 605asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg,
606 unsigned int vlen, unsigned flags); 606 unsigned int vlen, unsigned flags);
607asmlinkage long sys_recv(int, void __user *, size_t, unsigned); 607asmlinkage long sys_recv(int, void __user *, size_t, unsigned);
608asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, 608asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned,
609 struct sockaddr __user *, int __user *); 609 struct sockaddr __user *, int __user *);
610asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); 610asmlinkage long sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags);
611asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, 611asmlinkage 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/net/compat.c b/net/compat.c
index bc8aeefddf3f..562e920b07f0 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -740,7 +740,7 @@ COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, uns
740{ 740{
741 if (flags & MSG_CMSG_COMPAT) 741 if (flags & MSG_CMSG_COMPAT)
742 return -EINVAL; 742 return -EINVAL;
743 return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); 743 return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
744} 744}
745 745
746COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, 746COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
@@ -756,7 +756,7 @@ COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, uns
756{ 756{
757 if (flags & MSG_CMSG_COMPAT) 757 if (flags & MSG_CMSG_COMPAT)
758 return -EINVAL; 758 return -EINVAL;
759 return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); 759 return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
760} 760}
761 761
762COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags) 762COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
diff --git a/net/socket.c b/net/socket.c
index fe20c319a0bb..0ae8147e3acc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1989,8 +1989,11 @@ struct used_address {
1989}; 1989};
1990 1990
1991static int copy_msghdr_from_user(struct msghdr *kmsg, 1991static int copy_msghdr_from_user(struct msghdr *kmsg,
1992 struct msghdr __user *umsg) 1992 struct user_msghdr __user *umsg)
1993{ 1993{
1994 /* We are relying on the (currently) identical layouts. Once
1995 * the kernel-side changes, this place will need to be updated
1996 */
1994 if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) 1997 if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
1995 return -EFAULT; 1998 return -EFAULT;
1996 1999
@@ -2005,7 +2008,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
2005 return 0; 2008 return 0;
2006} 2009}
2007 2010
2008static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, 2011static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
2009 struct msghdr *msg_sys, unsigned int flags, 2012 struct msghdr *msg_sys, unsigned int flags,
2010 struct used_address *used_address) 2013 struct used_address *used_address)
2011{ 2014{
@@ -2123,7 +2126,7 @@ out:
2123 * BSD sendmsg interface 2126 * BSD sendmsg interface
2124 */ 2127 */
2125 2128
2126long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) 2129long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
2127{ 2130{
2128 int fput_needed, err; 2131 int fput_needed, err;
2129 struct msghdr msg_sys; 2132 struct msghdr msg_sys;
@@ -2140,7 +2143,7 @@ out:
2140 return err; 2143 return err;
2141} 2144}
2142 2145
2143SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) 2146SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags)
2144{ 2147{
2145 if (flags & MSG_CMSG_COMPAT) 2148 if (flags & MSG_CMSG_COMPAT)
2146 return -EINVAL; 2149 return -EINVAL;
@@ -2177,7 +2180,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
2177 2180
2178 while (datagrams < vlen) { 2181 while (datagrams < vlen) {
2179 if (MSG_CMSG_COMPAT & flags) { 2182 if (MSG_CMSG_COMPAT & flags) {
2180 err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, 2183 err = ___sys_sendmsg(sock, (struct user_msghdr __user *)compat_entry,
2181 &msg_sys, flags, &used_address); 2184 &msg_sys, flags, &used_address);
2182 if (err < 0) 2185 if (err < 0)
2183 break; 2186 break;
@@ -2185,7 +2188,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
2185 ++compat_entry; 2188 ++compat_entry;
2186 } else { 2189 } else {
2187 err = ___sys_sendmsg(sock, 2190 err = ___sys_sendmsg(sock,
2188 (struct msghdr __user *)entry, 2191 (struct user_msghdr __user *)entry,
2189 &msg_sys, flags, &used_address); 2192 &msg_sys, flags, &used_address);
2190 if (err < 0) 2193 if (err < 0)
2191 break; 2194 break;
@@ -2215,7 +2218,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
2215 return __sys_sendmmsg(fd, mmsg, vlen, flags); 2218 return __sys_sendmmsg(fd, mmsg, vlen, flags);
2216} 2219}
2217 2220
2218static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, 2221static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg,
2219 struct msghdr *msg_sys, unsigned int flags, int nosec) 2222 struct msghdr *msg_sys, unsigned int flags, int nosec)
2220{ 2223{
2221 struct compat_msghdr __user *msg_compat = 2224 struct compat_msghdr __user *msg_compat =
@@ -2311,7 +2314,7 @@ out:
2311 * BSD recvmsg interface 2314 * BSD recvmsg interface
2312 */ 2315 */
2313 2316
2314long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags) 2317long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
2315{ 2318{
2316 int fput_needed, err; 2319 int fput_needed, err;
2317 struct msghdr msg_sys; 2320 struct msghdr msg_sys;
@@ -2328,7 +2331,7 @@ out:
2328 return err; 2331 return err;
2329} 2332}
2330 2333
2331SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, 2334SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg,
2332 unsigned int, flags) 2335 unsigned int, flags)
2333{ 2336{
2334 if (flags & MSG_CMSG_COMPAT) 2337 if (flags & MSG_CMSG_COMPAT)
@@ -2373,7 +2376,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. 2376 * No need to ask LSM for more than the first datagram.
2374 */ 2377 */
2375 if (MSG_CMSG_COMPAT & flags) { 2378 if (MSG_CMSG_COMPAT & flags) {
2376 err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, 2379 err = ___sys_recvmsg(sock, (struct user_msghdr __user *)compat_entry,
2377 &msg_sys, flags & ~MSG_WAITFORONE, 2380 &msg_sys, flags & ~MSG_WAITFORONE,
2378 datagrams); 2381 datagrams);
2379 if (err < 0) 2382 if (err < 0)
@@ -2382,7 +2385,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
2382 ++compat_entry; 2385 ++compat_entry;
2383 } else { 2386 } else {
2384 err = ___sys_recvmsg(sock, 2387 err = ___sys_recvmsg(sock,
2385 (struct msghdr __user *)entry, 2388 (struct user_msghdr __user *)entry,
2386 &msg_sys, flags & ~MSG_WAITFORONE, 2389 &msg_sys, flags & ~MSG_WAITFORONE,
2387 datagrams); 2390 datagrams);
2388 if (err < 0) 2391 if (err < 0)
@@ -2571,13 +2574,13 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
2571 (int __user *)a[4]); 2574 (int __user *)a[4]);
2572 break; 2575 break;
2573 case SYS_SENDMSG: 2576 case SYS_SENDMSG:
2574 err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); 2577 err = sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2]);
2575 break; 2578 break;
2576 case SYS_SENDMMSG: 2579 case SYS_SENDMMSG:
2577 err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); 2580 err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
2578 break; 2581 break;
2579 case SYS_RECVMSG: 2582 case SYS_RECVMSG:
2580 err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 2583 err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]);
2581 break; 2584 break;
2582 case SYS_RECVMMSG: 2585 case SYS_RECVMMSG:
2583 err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], 2586 err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],