summaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c239
1 files changed, 166 insertions, 73 deletions
diff --git a/net/socket.c b/net/socket.c
index a93c99b518ca..4ba9fc631c43 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1332,7 +1332,7 @@ int sock_create_kern(struct net *net, int family, int type, int protocol, struct
}
EXPORT_SYMBOL(sock_create_kern);
-SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
+int __sys_socket(int family, int type, int protocol)
{
int retval;
struct socket *sock;
@@ -1359,12 +1359,16 @@ SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
return sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
}
+SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
+{
+ return __sys_socket(family, type, protocol);
+}
+
/*
* Create a pair of connected sockets.
*/
-SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
- int __user *, usockvec)
+int __sys_socketpair(int family, int type, int protocol, int __user *usockvec)
{
struct socket *sock1, *sock2;
int fd1, fd2, err;
@@ -1449,6 +1453,12 @@ out:
return err;
}
+SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
+ int __user *, usockvec)
+{
+ return __sys_socketpair(family, type, protocol, usockvec);
+}
+
/*
* Bind a name to a socket. Nothing much to do here since it's
* the protocol's responsibility to handle the local address.
@@ -1457,7 +1467,7 @@ out:
* the protocol layer (having also checked the address is ok).
*/
-SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
+int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
@@ -1480,13 +1490,18 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
return err;
}
+SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
+{
+ return __sys_bind(fd, umyaddr, addrlen);
+}
+
/*
* Perform a listen. Basically, we allow the protocol to do anything
* necessary for a listen, and if that works, we mark the socket as
* ready for listening.
*/
-SYSCALL_DEFINE2(listen, int, fd, int, backlog)
+int __sys_listen(int fd, int backlog)
{
struct socket *sock;
int err, fput_needed;
@@ -1507,6 +1522,11 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
return err;
}
+SYSCALL_DEFINE2(listen, int, fd, int, backlog)
+{
+ return __sys_listen(fd, backlog);
+}
+
/*
* For accept, we attempt to create a new socket, set up the link
* with the client, wake up the client, then return the new
@@ -1519,8 +1539,8 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
* clean when we restucture accept also.
*/
-SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
- int __user *, upeer_addrlen, int, flags)
+int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
+ int __user *upeer_addrlen, int flags)
{
struct socket *sock, *newsock;
struct file *newfile;
@@ -1599,10 +1619,16 @@ out_fd:
goto out_put;
}
+SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
+ int __user *, upeer_addrlen, int, flags)
+{
+ return __sys_accept4(fd, upeer_sockaddr, upeer_addrlen, flags);
+}
+
SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
int __user *, upeer_addrlen)
{
- return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0);
+ return __sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0);
}
/*
@@ -1617,8 +1643,7 @@ SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
* include the -EINPROGRESS status for such sockets.
*/
-SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
- int, addrlen)
+int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
@@ -1644,13 +1669,19 @@ out:
return err;
}
+SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
+ int, addrlen)
+{
+ return __sys_connect(fd, uservaddr, addrlen);
+}
+
/*
* Get the local address ('name') of a socket object. Move the obtained
* name to user space.
*/
-SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
- int __user *, usockaddr_len)
+int __sys_getsockname(int fd, struct sockaddr __user *usockaddr,
+ int __user *usockaddr_len)
{
struct socket *sock;
struct sockaddr_storage address;
@@ -1675,13 +1706,19 @@ out:
return err;
}
+SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
+ int __user *, usockaddr_len)
+{
+ return __sys_getsockname(fd, usockaddr, usockaddr_len);
+}
+
/*
* Get the remote address ('name') of a socket object. Move the obtained
* name to user space.
*/
-SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
- int __user *, usockaddr_len)
+int __sys_getpeername(int fd, struct sockaddr __user *usockaddr,
+ int __user *usockaddr_len)
{
struct socket *sock;
struct sockaddr_storage address;
@@ -1706,15 +1743,19 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
return err;
}
+SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
+ int __user *, usockaddr_len)
+{
+ return __sys_getpeername(fd, usockaddr, usockaddr_len);
+}
+
/*
* Send a datagram to a given address. We move the address into kernel
* space and check the user space data area is readable before invoking
* the protocol.
*/
-
-SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
- unsigned int, flags, struct sockaddr __user *, addr,
- int, addr_len)
+int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
+ struct sockaddr __user *addr, int addr_len)
{
struct socket *sock;
struct sockaddr_storage address;
@@ -1752,6 +1793,13 @@ out:
return err;
}
+SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
+ unsigned int, flags, struct sockaddr __user *, addr,
+ int, addr_len)
+{
+ return __sys_sendto(fd, buff, len, flags, addr, addr_len);
+}
+
/*
* Send a datagram down a socket.
*/
@@ -1759,7 +1807,7 @@ out:
SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
unsigned int, flags)
{
- return sys_sendto(fd, buff, len, flags, NULL, 0);
+ return __sys_sendto(fd, buff, len, flags, NULL, 0);
}
/*
@@ -1767,10 +1815,8 @@ SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
* sender. We verify the buffers are writable and if needed move the
* sender address from kernel to user space.
*/
-
-SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
- unsigned int, flags, struct sockaddr __user *, addr,
- int __user *, addr_len)
+int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
+ struct sockaddr __user *addr, int __user *addr_len)
{
struct socket *sock;
struct iovec iov;
@@ -1810,6 +1856,13 @@ out:
return err;
}
+SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
+ unsigned int, flags, struct sockaddr __user *, addr,
+ int __user *, addr_len)
+{
+ return __sys_recvfrom(fd, ubuf, size, flags, addr, addr_len);
+}
+
/*
* Receive a datagram from a socket.
*/
@@ -1817,7 +1870,7 @@ out:
SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size,
unsigned int, flags)
{
- return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
+ return __sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
}
/*
@@ -1825,8 +1878,8 @@ SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size,
* to pass the user mode parameter for the protocols to sort out.
*/
-SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
- char __user *, optval, int, optlen)
+static int __sys_setsockopt(int fd, int level, int optname,
+ char __user *optval, int optlen)
{
int err, fput_needed;
struct socket *sock;
@@ -1854,13 +1907,19 @@ out_put:
return err;
}
+SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, int, optlen)
+{
+ return __sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
/*
* Get a socket option. Because we don't know the option lengths we have
* to pass a user mode parameter for the protocols to sort out.
*/
-SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
- char __user *, optval, int __user *, optlen)
+static int __sys_getsockopt(int fd, int level, int optname,
+ char __user *optval, int __user *optlen)
{
int err, fput_needed;
struct socket *sock;
@@ -1885,11 +1944,17 @@ out_put:
return err;
}
+SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, int __user *, optlen)
+{
+ return __sys_getsockopt(fd, level, optname, optval, optlen);
+}
+
/*
* Shutdown a socket.
*/
-SYSCALL_DEFINE2(shutdown, int, fd, int, how)
+int __sys_shutdown(int fd, int how)
{
int err, fput_needed;
struct socket *sock;
@@ -1904,6 +1969,11 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how)
return err;
}
+SYSCALL_DEFINE2(shutdown, int, fd, int, how)
+{
+ return __sys_shutdown(fd, how);
+}
+
/* A couple of helpful macros for getting the address of the 32/64 bit
* fields which are the same type (int / unsigned) on our platforms.
*/
@@ -2067,12 +2137,16 @@ out_freeiov:
* BSD sendmsg interface
*/
-long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
+long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags,
+ bool forbid_cmsg_compat)
{
int fput_needed, err;
struct msghdr msg_sys;
struct socket *sock;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT))
+ return -EINVAL;
+
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -2086,9 +2160,7 @@ out:
SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags)
{
- if (flags & MSG_CMSG_COMPAT)
- return -EINVAL;
- return __sys_sendmsg(fd, msg, flags);
+ return __sys_sendmsg(fd, msg, flags, true);
}
/*
@@ -2096,7 +2168,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int
*/
int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
- unsigned int flags)
+ unsigned int flags, bool forbid_cmsg_compat)
{
int fput_needed, err, datagrams;
struct socket *sock;
@@ -2106,6 +2178,9 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
struct used_address used_address;
unsigned int oflags = flags;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT))
+ return -EINVAL;
+
if (vlen > UIO_MAXIOV)
vlen = UIO_MAXIOV;
@@ -2162,9 +2237,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
unsigned int, vlen, unsigned int, flags)
{
- if (flags & MSG_CMSG_COMPAT)
- return -EINVAL;
- return __sys_sendmmsg(fd, mmsg, vlen, flags);
+ return __sys_sendmmsg(fd, mmsg, vlen, flags, true);
}
static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg,
@@ -2237,12 +2310,16 @@ out_freeiov:
* BSD recvmsg interface
*/
-long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
+long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags,
+ bool forbid_cmsg_compat)
{
int fput_needed, err;
struct msghdr msg_sys;
struct socket *sock;
+ if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT))
+ return -EINVAL;
+
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -2257,9 +2334,7 @@ out:
SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg,
unsigned int, flags)
{
- if (flags & MSG_CMSG_COMPAT)
- return -EINVAL;
- return __sys_recvmsg(fd, msg, flags);
+ return __sys_recvmsg(fd, msg, flags, true);
}
/*
@@ -2375,9 +2450,9 @@ out_put:
return datagrams;
}
-SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
- unsigned int, vlen, unsigned int, flags,
- struct timespec __user *, timeout)
+static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
+ unsigned int vlen, unsigned int flags,
+ struct timespec __user *timeout)
{
int datagrams;
struct timespec timeout_sys;
@@ -2400,6 +2475,13 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
return datagrams;
}
+SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags,
+ struct timespec __user *, timeout)
+{
+ return do_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
+}
+
#ifdef __ARCH_WANT_SYS_SOCKETCALL
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
@@ -2447,76 +2529,82 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
switch (call) {
case SYS_SOCKET:
- err = sys_socket(a0, a1, a[2]);
+ err = __sys_socket(a0, a1, a[2]);
break;
case SYS_BIND:
- err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
+ err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
break;
case SYS_CONNECT:
- err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
+ err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
break;
case SYS_LISTEN:
- err = sys_listen(a0, a1);
+ err = __sys_listen(a0, a1);
break;
case SYS_ACCEPT:
- err = sys_accept4(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2], 0);
+ err = __sys_accept4(a0, (struct sockaddr __user *)a1,
+ (int __user *)a[2], 0);
break;
case SYS_GETSOCKNAME:
err =
- sys_getsockname(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
+ __sys_getsockname(a0, (struct sockaddr __user *)a1,
+ (int __user *)a[2]);
break;
case SYS_GETPEERNAME:
err =
- sys_getpeername(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
+ __sys_getpeername(a0, (struct sockaddr __user *)a1,
+ (int __user *)a[2]);
break;
case SYS_SOCKETPAIR:
- err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
+ err = __sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
break;
case SYS_SEND:
- err = sys_send(a0, (void __user *)a1, a[2], a[3]);
+ err = __sys_sendto(a0, (void __user *)a1, a[2], a[3],
+ NULL, 0);
break;
case SYS_SENDTO:
- err = sys_sendto(a0, (void __user *)a1, a[2], a[3],
- (struct sockaddr __user *)a[4], a[5]);
+ err = __sys_sendto(a0, (void __user *)a1, a[2], a[3],
+ (struct sockaddr __user *)a[4], a[5]);
break;
case SYS_RECV:
- err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
+ err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
+ NULL, NULL);
break;
case SYS_RECVFROM:
- err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
- (struct sockaddr __user *)a[4],
- (int __user *)a[5]);
+ err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
+ (struct sockaddr __user *)a[4],
+ (int __user *)a[5]);
break;
case SYS_SHUTDOWN:
- err = sys_shutdown(a0, a1);
+ err = __sys_shutdown(a0, a1);
break;
case SYS_SETSOCKOPT:
- err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
+ err = __sys_setsockopt(a0, a1, a[2], (char __user *)a[3],
+ a[4]);
break;
case SYS_GETSOCKOPT:
err =
- sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
- (int __user *)a[4]);
+ __sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
+ (int __user *)a[4]);
break;
case SYS_SENDMSG:
- err = sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2]);
+ err = __sys_sendmsg(a0, (struct user_msghdr __user *)a1,
+ a[2], true);
break;
case SYS_SENDMMSG:
- err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
+ err = __sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2],
+ a[3], true);
break;
case SYS_RECVMSG:
- err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]);
+ err = __sys_recvmsg(a0, (struct user_msghdr __user *)a1,
+ a[2], true);
break;
case SYS_RECVMMSG:
- err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
- (struct timespec __user *)a[4]);
+ err = do_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2],
+ a[3], (struct timespec __user *)a[4]);
break;
case SYS_ACCEPT4:
- err = sys_accept4(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2], a[3]);
+ err = __sys_accept4(a0, (struct sockaddr __user *)a1,
+ (int __user *)a[2], a[3]);
break;
default:
err = -EINVAL;
@@ -2587,6 +2675,11 @@ void sock_unregister(int family)
}
EXPORT_SYMBOL(sock_unregister);
+bool sock_is_registered(int family)
+{
+ return family < NPROTO && rcu_access_pointer(net_families[family]);
+}
+
static int __init sock_init(void)
{
int err;