summaryrefslogtreecommitdiff
path: root/net/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c115
1 files changed, 34 insertions, 81 deletions
diff --git a/net/socket.c b/net/socket.c
index e8892b218708..42fc3028e891 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -503,21 +503,12 @@ EXPORT_SYMBOL(sock_alloc_file);
static int sock_map_fd(struct socket *sock, int flags)
{
- struct file *newfile;
- int fd = get_unused_fd_flags(flags);
- if (unlikely(fd < 0)) {
- sock_release(sock);
- return fd;
- }
+ int fd;
- newfile = sock_alloc_file(sock, flags, NULL);
- if (!IS_ERR(newfile)) {
- fd_install(fd, newfile);
- return fd;
- }
-
- put_unused_fd(fd);
- return PTR_ERR(newfile);
+ fd = FD_ADD(flags, sock_alloc_file(sock, flags, NULL));
+ if (fd < 0)
+ sock_release(sock);
+ return fd;
}
/**
@@ -1872,7 +1863,7 @@ int __sys_bind_socket(struct socket *sock, struct sockaddr_storage *address,
addrlen);
if (!err)
err = READ_ONCE(sock->ops)->bind(sock,
- (struct sockaddr *)address,
+ (struct sockaddr_unsized *)address,
addrlen);
return err;
}
@@ -2012,8 +2003,6 @@ static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_s
int __user *upeer_addrlen, int flags)
{
struct proto_accept_arg arg = { };
- struct file *newfile;
- int newfd;
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
@@ -2021,18 +2010,7 @@ static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_s
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
- newfd = get_unused_fd_flags(flags);
- if (unlikely(newfd < 0))
- return newfd;
-
- newfile = do_accept(file, &arg, upeer_sockaddr, upeer_addrlen,
- flags);
- if (IS_ERR(newfile)) {
- put_unused_fd(newfd);
- return PTR_ERR(newfile);
- }
- fd_install(newfd, newfile);
- return newfd;
+ return FD_ADD(flags, do_accept(file, &arg, upeer_sockaddr, upeer_addrlen, flags));
}
/*
@@ -2099,8 +2077,8 @@ int __sys_connect_file(struct file *file, struct sockaddr_storage *address,
if (err)
goto out;
- err = READ_ONCE(sock->ops)->connect(sock, (struct sockaddr *)address,
- addrlen, sock->file->f_flags | file_flags);
+ err = READ_ONCE(sock->ops)->connect(sock, (struct sockaddr_unsized *)address,
+ addrlen, sock->file->f_flags | file_flags);
out:
return err;
}
@@ -2127,78 +2105,53 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
return __sys_connect(fd, uservaddr, addrlen);
}
-/*
- * Get the local address ('name') of a socket object. Move the obtained
- * name to user space.
- */
-
-int __sys_getsockname(int fd, struct sockaddr __user *usockaddr,
- int __user *usockaddr_len)
+int do_getsockname(struct socket *sock, int peer,
+ struct sockaddr __user *usockaddr, int __user *usockaddr_len)
{
- struct socket *sock;
struct sockaddr_storage address;
- CLASS(fd, f)(fd);
int err;
- if (fd_empty(f))
- return -EBADF;
- sock = sock_from_file(fd_file(f));
- if (unlikely(!sock))
- return -ENOTSOCK;
-
- err = security_socket_getsockname(sock);
+ if (peer)
+ err = security_socket_getpeername(sock);
+ else
+ err = security_socket_getsockname(sock);
if (err)
return err;
-
- err = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, 0);
+ err = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, peer);
if (err < 0)
return err;
-
/* "err" is actually length in this case */
return move_addr_to_user(&address, err, usockaddr, usockaddr_len);
}
-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.
+ * Get the remote or local address ('name') of a socket object. Move the
+ * obtained name to user space.
*/
-
-int __sys_getpeername(int fd, struct sockaddr __user *usockaddr,
- int __user *usockaddr_len)
+int __sys_getsockname(int fd, struct sockaddr __user *usockaddr,
+ int __user *usockaddr_len, int peer)
{
struct socket *sock;
- struct sockaddr_storage address;
CLASS(fd, f)(fd);
- int err;
if (fd_empty(f))
return -EBADF;
sock = sock_from_file(fd_file(f));
if (unlikely(!sock))
return -ENOTSOCK;
+ return do_getsockname(sock, peer, usockaddr, usockaddr_len);
+}
- err = security_socket_getpeername(sock);
- if (err)
- return err;
-
- err = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, 1);
- if (err < 0)
- return err;
-
- /* "err" is actually length in this case */
- return move_addr_to_user(&address, err, usockaddr, usockaddr_len);
+SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
+ int __user *, usockaddr_len)
+{
+ return __sys_getsockname(fd, usockaddr, usockaddr_len, 0);
}
SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
int __user *, usockaddr_len)
{
- return __sys_getpeername(fd, usockaddr, usockaddr_len);
+ return __sys_getsockname(fd, usockaddr, usockaddr_len, 1);
}
/*
@@ -3162,12 +3115,12 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
case SYS_GETSOCKNAME:
err =
__sys_getsockname(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
+ (int __user *)a[2], 0);
break;
case SYS_GETPEERNAME:
err =
- __sys_getpeername(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
+ __sys_getsockname(a0, (struct sockaddr __user *)a1,
+ (int __user *)a[2], 1);
break;
case SYS_SOCKETPAIR:
err = __sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
@@ -3583,13 +3536,13 @@ static long compat_sock_ioctl(struct file *file, unsigned int cmd,
* Returns 0 or an error.
*/
-int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
+int kernel_bind(struct socket *sock, struct sockaddr_unsized *addr, int addrlen)
{
struct sockaddr_storage address;
memcpy(&address, addr, addrlen);
- return READ_ONCE(sock->ops)->bind(sock, (struct sockaddr *)&address,
+ return READ_ONCE(sock->ops)->bind(sock, (struct sockaddr_unsized *)&address,
addrlen);
}
EXPORT_SYMBOL(kernel_bind);
@@ -3662,14 +3615,14 @@ EXPORT_SYMBOL(kernel_accept);
* Returns 0 or an error code.
*/
-int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
+int kernel_connect(struct socket *sock, struct sockaddr_unsized *addr, int addrlen,
int flags)
{
struct sockaddr_storage address;
memcpy(&address, addr, addrlen);
- return READ_ONCE(sock->ops)->connect(sock, (struct sockaddr *)&address,
+ return READ_ONCE(sock->ops)->connect(sock, (struct sockaddr_unsized *)&address,
addrlen, flags);
}
EXPORT_SYMBOL(kernel_connect);