2020-07-30 23:01:41 +00:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-07-30 23:01:41 +00:00
*/
2023-02-13 23:01:13 +00:00
# include <AK/ByteBuffer.h>
2021-09-07 11:39:11 +00:00
# include <Kernel/FileSystem/OpenFileDescription.h>
2020-07-30 21:38:15 +00:00
# include <Kernel/Net/LocalSocket.h>
2023-02-24 17:45:37 +00:00
# include <Kernel/Tasks/Process.h>
2020-09-16 15:45:00 +00:00
# include <Kernel/UnixTypes.h>
2020-07-30 21:38:15 +00:00
namespace Kernel {
# define REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain) \
do { \
if ( domain = = AF_INET ) \
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : inet ) ) ; \
2020-07-30 21:38:15 +00:00
else if ( domain = = AF_LOCAL ) \
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : unix ) ) ; \
2020-07-30 21:38:15 +00:00
} while ( 0 )
2023-03-06 18:29:25 +00:00
static void setup_socket_fd ( Process : : OpenFileDescriptions & fds , int fd , NonnullRefPtr < OpenFileDescription > description , int type )
2021-04-28 10:39:12 +00:00
{
description - > set_readable ( true ) ;
description - > set_writable ( true ) ;
unsigned flags = 0 ;
if ( type & SOCK_CLOEXEC )
flags | = FD_CLOEXEC ;
if ( type & SOCK_NONBLOCK )
description - > set_blocking ( false ) ;
2022-01-29 00:22:28 +00:00
fds [ fd ] . set ( * description , flags ) ;
2021-04-28 10:39:12 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < FlatPtr > Process : : sys $ socket ( int domain , int type , int protocol )
2020-07-30 21:38:15 +00:00
{
2022-08-21 14:59:31 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2020-07-30 21:38:15 +00:00
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( domain ) ;
2022-08-20 22:21:01 +00:00
auto credentials = this - > credentials ( ) ;
if ( ( type & SOCK_TYPE_MASK ) = = SOCK_RAW & & ! credentials - > is_superuser ( ) )
2021-03-01 12:49:16 +00:00
return EACCES ;
2022-01-29 00:22:28 +00:00
2022-01-29 00:29:07 +00:00
return m_fds . with_exclusive ( [ & ] ( auto & fds ) - > ErrorOr < FlatPtr > {
2022-01-29 00:22:28 +00:00
auto fd_allocation = TRY ( fds . allocate ( ) ) ;
auto socket = TRY ( Socket : : create ( domain , type , protocol ) ) ;
auto description = TRY ( OpenFileDescription : : try_create ( socket ) ) ;
setup_socket_fd ( fds , fd_allocation . fd , move ( description ) , type ) ;
return fd_allocation . fd ;
} ) ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ bind ( int sockfd , Userspace < sockaddr const * > address , socklen_t address_length )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2022-04-03 20:20:34 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
if ( ! description - > is_socket ( ) )
return ENOTSOCK ;
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2022-08-21 14:33:09 +00:00
TRY ( socket . bind ( credentials ( ) , address , address_length ) ) ;
2022-04-03 20:20:34 +00:00
return 0 ;
2020-07-30 21:38:15 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < FlatPtr > Process : : sys $ listen ( int sockfd , int backlog )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2023-11-25 14:36:08 +00:00
// As per POSIX, the behavior of listen() with a backlog value of 0 is implementation defined:
// "A backlog argument of 0 may allow the socket to accept connections, in which case the length of the listen queue may be set to an implementation-defined minimum value."
// Since creating a socket that can't accept any connections seems relatively useless, and as other platforms (Linux, FreeBSD, etc) chose to support accepting connections
// with this backlog value, support it as well by normalizing it to 1.
// Also, as per POSIX, the behaviour of a negative backlog value is equivalent to a backlog value of 0:
// "If listen() is called with a backlog argument value that is less than 0, the function behaves as if it had been called with a backlog argument value of 0."
if ( backlog < = 0 )
backlog = 1 ;
2022-04-03 20:18:57 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
if ( ! description - > is_socket ( ) )
return ENOTSOCK ;
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
if ( socket . is_connected ( ) )
return EINVAL ;
TRY ( socket . listen ( backlog ) ) ;
return 0 ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ accept4 ( Userspace < Syscall : : SC_accept4_params const * > user_params )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : accept ) ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2021-05-16 17:56:11 +00:00
int accepting_socket_fd = params . sockfd ;
Userspace < sockaddr * > user_address ( ( FlatPtr ) params . addr ) ;
Userspace < socklen_t * > user_address_size ( ( FlatPtr ) params . addrlen ) ;
int flags = params . flags ;
2020-07-30 21:38:15 +00:00
socklen_t address_size = 0 ;
2022-04-09 15:28:31 +00:00
if ( user_address )
2022-04-01 17:58:27 +00:00
TRY ( copy_from_user ( & address_size , static_ptr_cast < socklen_t const * > ( user_address_size ) ) ) ;
2020-07-30 21:38:15 +00:00
2022-01-29 00:22:28 +00:00
ScopedDescriptionAllocation fd_allocation ;
2023-03-06 18:29:25 +00:00
RefPtr < OpenFileDescription > accepting_socket_description ;
2022-01-29 00:22:28 +00:00
2022-01-29 00:29:07 +00:00
TRY ( m_fds . with_exclusive ( [ & ] ( auto & fds ) - > ErrorOr < void > {
2022-01-29 00:22:28 +00:00
fd_allocation = TRY ( fds . allocate ( ) ) ;
accepting_socket_description = TRY ( fds . open_file_description ( accepting_socket_fd ) ) ;
return { } ;
} ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! accepting_socket_description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * accepting_socket_description - > socket ( ) ;
2022-08-19 18:53:40 +00:00
LockRefPtr < Socket > accepted_socket ;
2022-04-09 15:28:31 +00:00
for ( ; ; ) {
accepted_socket = socket . accept ( ) ;
if ( accepted_socket )
break ;
if ( ! accepting_socket_description - > is_blocking ( ) )
2021-03-01 12:49:16 +00:00
return EAGAIN ;
2022-04-09 15:28:31 +00:00
auto unblock_flags = Thread : : FileBlocker : : BlockFlags : : None ;
if ( Thread : : current ( ) - > block < Thread : : AcceptBlocker > ( { } , * accepting_socket_description , unblock_flags ) . was_interrupted ( ) )
return EINTR ;
2020-07-30 21:38:15 +00:00
}
if ( user_address ) {
2021-12-29 10:54:25 +00:00
sockaddr_un address_buffer { } ;
2020-07-30 21:38:15 +00:00
address_size = min ( sizeof ( sockaddr_un ) , static_cast < size_t > ( address_size ) ) ;
2021-07-01 09:29:28 +00:00
accepted_socket - > get_peer_address ( ( sockaddr * ) & address_buffer , & address_size ) ;
2021-09-05 15:38:37 +00:00
TRY ( copy_to_user ( user_address , & address_buffer , address_size ) ) ;
TRY ( copy_to_user ( user_address_size , & address_size ) ) ;
2020-07-30 21:38:15 +00:00
}
2021-09-07 11:39:11 +00:00
auto accepted_socket_description = TRY ( OpenFileDescription : : try_create ( * accepted_socket ) ) ;
2020-09-17 19:51:09 +00:00
2021-09-05 13:54:53 +00:00
accepted_socket_description - > set_readable ( true ) ;
accepted_socket_description - > set_writable ( true ) ;
2021-05-16 17:56:11 +00:00
if ( flags & SOCK_NONBLOCK )
2021-09-05 13:54:53 +00:00
accepted_socket_description - > set_blocking ( false ) ;
2021-05-16 17:56:11 +00:00
int fd_flags = 0 ;
if ( flags & SOCK_CLOEXEC )
fd_flags | = FD_CLOEXEC ;
2022-01-29 00:22:28 +00:00
2022-01-29 00:29:07 +00:00
TRY ( m_fds . with_exclusive ( [ & ] ( auto & fds ) - > ErrorOr < void > {
2022-01-29 00:22:28 +00:00
fds [ fd_allocation . fd ] . set ( move ( accepted_socket_description ) , fd_flags ) ;
return { } ;
} ) ) ;
2020-07-30 21:38:15 +00:00
// NOTE: Moving this state to Completed is what causes connect() to unblock on the client side.
accepted_socket - > set_setup_state ( Socket : : SetupState : : Completed ) ;
2021-09-05 13:54:53 +00:00
return fd_allocation . fd ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ connect ( int sockfd , Userspace < sockaddr const * > user_address , socklen_t user_address_size )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2022-08-21 14:35:03 +00:00
TRY ( socket . connect ( credentials ( ) , * description , user_address , user_address_size ) ) ;
2021-11-07 23:51:39 +00:00
return 0 ;
2020-07-30 21:38:15 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < FlatPtr > Process : : sys $ shutdown ( int sockfd , int how )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : stdio ) ) ;
2022-07-09 19:26:58 +00:00
if ( how ! = SHUT_RD & & how ! = SHUT_WR & & how ! = SHUT_RDWR )
2021-03-01 12:49:16 +00:00
return EINVAL ;
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2021-11-07 23:51:39 +00:00
TRY ( socket . shutdown ( how ) ) ;
return 0 ;
2020-07-30 21:38:15 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < FlatPtr > Process : : sys $ sendmsg ( int sockfd , Userspace < const struct msghdr * > user_msg , int flags )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : stdio ) ) ;
2021-12-17 08:12:20 +00:00
auto msg = TRY ( copy_typed_from_user ( user_msg ) ) ;
2020-07-30 21:38:15 +00:00
2020-09-16 15:45:00 +00:00
if ( msg . msg_iovlen ! = 1 )
2021-03-01 12:49:16 +00:00
return ENOTSUP ; // FIXME: Support this :)
2020-09-16 15:45:00 +00:00
Vector < iovec , 1 > iovs ;
2021-11-10 10:55:37 +00:00
TRY ( iovs . try_resize ( msg . msg_iovlen ) ) ;
2021-09-05 15:38:37 +00:00
TRY ( copy_n_from_user ( iovs . data ( ) , msg . msg_iov , msg . msg_iovlen ) ) ;
2021-06-16 14:44:15 +00:00
if ( iovs [ 0 ] . iov_len > NumericLimits < ssize_t > : : max ( ) )
return EINVAL ;
2020-09-16 15:45:00 +00:00
2022-04-01 17:58:27 +00:00
Userspace < sockaddr const * > user_addr ( ( FlatPtr ) msg . msg_name ) ;
2020-09-16 15:45:00 +00:00
socklen_t addr_length = msg . msg_namelen ;
2020-07-30 21:38:15 +00:00
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2022-02-07 11:03:34 +00:00
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
2022-10-23 08:30:12 +00:00
if ( socket . is_shut_down_for_writing ( ) ) {
if ( ( flags & MSG_NOSIGNAL ) = = 0 )
Thread : : current ( ) - > send_signal ( SIGPIPE , & Process : : current ( ) ) ;
2021-03-01 12:49:16 +00:00
return EPIPE ;
2022-10-23 08:30:12 +00:00
}
2023-02-13 23:01:13 +00:00
if ( msg . msg_controllen > 0 ) {
// Handle command messages.
auto cmsg_buffer = TRY ( ByteBuffer : : create_uninitialized ( msg . msg_controllen ) ) ;
TRY ( copy_from_user ( cmsg_buffer . data ( ) , msg . msg_control , msg . msg_controllen ) ) ;
msg . msg_control = cmsg_buffer . data ( ) ;
for ( struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & msg ) ; cmsg ! = nullptr ; cmsg = CMSG_NXTHDR ( & msg , cmsg ) ) {
if ( socket . is_local ( ) & & cmsg - > cmsg_level = = SOL_SOCKET & & cmsg - > cmsg_type = = SCM_RIGHTS ) {
auto & local_socket = static_cast < LocalSocket & > ( socket ) ;
int * fds = ( int * ) CMSG_DATA ( cmsg ) ;
size_t nfds = ( cmsg - > cmsg_len - CMSG_ALIGN ( sizeof ( struct cmsghdr ) ) ) / sizeof ( int ) ;
for ( size_t i = 0 ; i < nfds ; + + i ) {
TRY ( local_socket . sendfd ( * description , TRY ( open_file_description ( fds [ i ] ) ) ) ) ;
}
}
}
}
2021-11-21 11:24:32 +00:00
auto data_buffer = TRY ( UserOrKernelBuffer : : for_user_buffer ( ( u8 * ) iovs [ 0 ] . iov_base , iovs [ 0 ] . iov_len ) ) ;
2022-02-07 11:03:34 +00:00
while ( true ) {
while ( ! description - > can_write ( ) ) {
if ( ! description - > is_blocking ( ) ) {
return EAGAIN ;
}
auto unblock_flags = Thread : : FileBlocker : : BlockFlags : : None ;
if ( Thread : : current ( ) - > block < Thread : : WriteBlocker > ( { } , * description , unblock_flags ) . was_interrupted ( ) ) {
return EINTR ;
}
// TODO: handle exceptions in unblock_flags
}
2022-10-23 08:30:12 +00:00
auto bytes_sent_or_error = socket . sendto ( * description , data_buffer , iovs [ 0 ] . iov_len , flags , user_addr , addr_length ) ;
if ( bytes_sent_or_error . is_error ( ) ) {
if ( ( flags & MSG_NOSIGNAL ) = = 0 & & bytes_sent_or_error . error ( ) . code ( ) = = EPIPE )
Thread : : current ( ) - > send_signal ( SIGPIPE , & Process : : current ( ) ) ;
return bytes_sent_or_error . release_error ( ) ;
}
auto bytes_sent = bytes_sent_or_error . release_value ( ) ;
2022-02-07 11:03:34 +00:00
if ( bytes_sent > 0 )
return bytes_sent ;
}
2020-07-30 21:38:15 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < FlatPtr > Process : : sys $ recvmsg ( int sockfd , Userspace < struct msghdr * > user_msg , int flags )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2021-12-29 09:11:45 +00:00
TRY ( require_promise ( Pledge : : stdio ) ) ;
2020-07-30 21:38:15 +00:00
2020-09-16 15:45:00 +00:00
struct msghdr msg ;
2021-09-05 15:38:37 +00:00
TRY ( copy_from_user ( & msg , user_msg ) ) ;
2020-07-30 21:38:15 +00:00
2020-09-16 15:45:00 +00:00
if ( msg . msg_iovlen ! = 1 )
2021-03-01 12:49:16 +00:00
return ENOTSUP ; // FIXME: Support this :)
2020-09-16 15:45:00 +00:00
Vector < iovec , 1 > iovs ;
2021-11-10 10:55:37 +00:00
TRY ( iovs . try_resize ( msg . msg_iovlen ) ) ;
2021-09-05 15:38:37 +00:00
TRY ( copy_n_from_user ( iovs . data ( ) , msg . msg_iov , msg . msg_iovlen ) ) ;
2020-09-16 15:45:00 +00:00
Userspace < sockaddr * > user_addr ( ( FlatPtr ) msg . msg_name ) ;
Userspace < socklen_t * > user_addr_length ( msg . msg_name ? ( FlatPtr ) & user_msg . unsafe_userspace_ptr ( ) - > msg_namelen : 0 ) ;
2020-09-12 03:11:07 +00:00
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
if ( socket . is_shut_down_for_reading ( ) )
return 0 ;
2021-11-21 11:24:32 +00:00
auto data_buffer = TRY ( UserOrKernelBuffer : : for_user_buffer ( ( u8 * ) iovs [ 0 ] . iov_base , iovs [ 0 ] . iov_len ) ) ;
2023-03-13 21:11:13 +00:00
UnixDateTime timestamp { } ;
2022-08-21 14:45:42 +00:00
bool blocking = ( flags & MSG_DONTWAIT ) ? false : description - > is_blocking ( ) ;
auto result = socket . recvfrom ( * description , data_buffer , iovs [ 0 ] . iov_len , flags , user_addr , user_addr_length , timestamp , blocking ) ;
2020-07-30 21:38:15 +00:00
2020-08-04 16:02:23 +00:00
if ( result . is_error ( ) )
2021-11-07 23:51:39 +00:00
return result . release_error ( ) ;
2020-09-16 15:45:00 +00:00
int msg_flags = 0 ;
if ( result . value ( ) > iovs [ 0 ] . iov_len ) {
2021-02-23 19:42:32 +00:00
VERIFY ( socket . type ( ) ! = SOCK_STREAM ) ;
2020-09-16 15:45:00 +00:00
msg_flags | = MSG_TRUNC ;
}
2023-02-13 23:01:13 +00:00
socklen_t current_cmsg_len = 0 ;
auto try_add_cmsg = [ & ] ( int level , int type , void const * data , socklen_t len ) - > ErrorOr < bool > {
if ( current_cmsg_len + len > msg . msg_controllen ) {
2020-09-16 16:32:45 +00:00
msg_flags | = MSG_CTRUNC ;
2023-02-13 23:01:13 +00:00
return false ;
2020-09-16 16:32:45 +00:00
}
2023-02-13 23:01:13 +00:00
cmsghdr cmsg = { ( socklen_t ) CMSG_LEN ( len ) , level , type } ;
cmsghdr * target = ( cmsghdr * ) ( ( ( char * ) msg . msg_control ) + current_cmsg_len ) ;
TRY ( copy_to_user ( target , & cmsg ) ) ;
TRY ( copy_to_user ( CMSG_DATA ( target ) , data , len ) ) ;
current_cmsg_len + = CMSG_ALIGN ( cmsg . cmsg_len ) ;
return true ;
} ;
if ( socket . wants_timestamp ( ) ) {
timeval time = timestamp . to_timeval ( ) ;
TRY ( try_add_cmsg ( SOL_SOCKET , SCM_TIMESTAMP , & time , sizeof ( time ) ) ) ;
}
int space_for_fds = ( msg . msg_controllen - current_cmsg_len - sizeof ( struct cmsghdr ) ) / sizeof ( int ) ;
if ( space_for_fds > 0 & & socket . is_local ( ) ) {
auto & local_socket = static_cast < LocalSocket & > ( socket ) ;
auto descriptions = TRY ( local_socket . recvfds ( description , space_for_fds ) ) ;
Vector < int > fdnums ;
for ( auto & description : descriptions ) {
auto fd_allocation = TRY ( m_fds . with_exclusive ( [ ] ( auto & fds ) { return fds . allocate ( ) ; } ) ) ;
2023-03-06 16:56:28 +00:00
m_fds . with_exclusive ( [ & ] ( auto & fds ) { fds [ fd_allocation . fd ] . set ( * description , 0 ) ; } ) ;
2023-02-13 23:01:13 +00:00
fdnums . append ( fd_allocation . fd ) ;
}
TRY ( try_add_cmsg ( SOL_SOCKET , SCM_RIGHTS , fdnums . data ( ) , fdnums . size ( ) * sizeof ( int ) ) ) ;
2020-09-16 16:32:45 +00:00
}
2023-02-13 23:01:13 +00:00
TRY ( copy_to_user ( & user_msg . unsafe_userspace_ptr ( ) - > msg_controllen , & current_cmsg_len ) ) ;
2021-09-05 15:38:37 +00:00
TRY ( copy_to_user ( & user_msg . unsafe_userspace_ptr ( ) - > msg_flags , & msg_flags ) ) ;
2020-08-04 16:02:23 +00:00
return result . value ( ) ;
2020-07-30 21:38:15 +00:00
}
2023-04-03 16:26:46 +00:00
template < Process : : SockOrPeerName sock_or_peer_name , typename Params >
2022-04-01 17:58:27 +00:00
ErrorOr < void > Process : : get_sock_or_peer_name ( Params const & params )
2020-07-30 21:38:15 +00:00
{
socklen_t addrlen_value ;
2021-09-05 15:38:37 +00:00
TRY ( copy_from_user ( & addrlen_value , params . addrlen , sizeof ( socklen_t ) ) ) ;
2020-07-30 21:38:15 +00:00
if ( addrlen_value < = 0 )
2021-03-01 12:49:16 +00:00
return EINVAL ;
2020-07-30 21:38:15 +00:00
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( params . sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2021-12-29 10:54:25 +00:00
sockaddr_un address_buffer { } ;
2020-07-30 21:38:15 +00:00
addrlen_value = min ( sizeof ( sockaddr_un ) , static_cast < size_t > ( addrlen_value ) ) ;
2023-04-03 16:26:46 +00:00
if constexpr ( sock_or_peer_name = = SockOrPeerName : : SockName )
2021-07-01 09:29:28 +00:00
socket . get_local_address ( ( sockaddr * ) & address_buffer , & addrlen_value ) ;
2020-07-30 21:38:15 +00:00
else
2021-07-01 09:29:28 +00:00
socket . get_peer_address ( ( sockaddr * ) & address_buffer , & addrlen_value ) ;
2021-09-05 15:38:37 +00:00
TRY ( copy_to_user ( params . addr , & address_buffer , addrlen_value ) ) ;
return copy_to_user ( params . addrlen , & addrlen_value ) ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ getsockname ( Userspace < Syscall : : SC_getsockname_params const * > user_params )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2023-04-03 16:26:46 +00:00
TRY ( get_sock_or_peer_name < SockOrPeerName : : SockName > ( params ) ) ;
2021-11-07 23:51:39 +00:00
return 0 ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ getpeername ( Userspace < Syscall : : SC_getpeername_params const * > user_params )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2023-04-03 16:26:46 +00:00
TRY ( get_sock_or_peer_name < SockOrPeerName : : PeerName > ( params ) ) ;
2021-11-07 23:51:39 +00:00
return 0 ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ getsockopt ( Userspace < Syscall : : SC_getsockopt_params const * > user_params )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2020-07-30 21:38:15 +00:00
2020-08-07 09:29:05 +00:00
int sockfd = params . sockfd ;
int level = params . level ;
int option = params . option ;
2020-09-12 03:11:07 +00:00
Userspace < void * > user_value ( ( FlatPtr ) params . value ) ;
Userspace < socklen_t * > user_value_size ( ( FlatPtr ) params . value_size ) ;
2020-07-30 21:38:15 +00:00
2020-08-07 09:29:05 +00:00
socklen_t value_size ;
2021-09-05 15:38:37 +00:00
TRY ( copy_from_user ( & value_size , params . value_size , sizeof ( socklen_t ) ) ) ;
2020-09-12 03:11:07 +00:00
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
2021-01-31 08:27:36 +00:00
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2021-11-07 23:51:39 +00:00
TRY ( socket . getsockopt ( * description , level , option , user_value , user_value_size ) ) ;
return 0 ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ setsockopt ( Userspace < Syscall : : SC_setsockopt_params const * > user_params )
2020-07-30 21:38:15 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2022-04-01 17:58:27 +00:00
Userspace < void const * > user_value ( ( FlatPtr ) params . value ) ;
2022-01-29 00:22:28 +00:00
auto description = TRY ( open_file_description ( params . sockfd ) ) ;
2020-07-30 21:38:15 +00:00
if ( ! description - > is_socket ( ) )
2021-03-01 12:49:16 +00:00
return ENOTSOCK ;
2020-07-30 21:38:15 +00:00
auto & socket = * description - > socket ( ) ;
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN ( socket . domain ( ) ) ;
2021-11-07 23:51:39 +00:00
TRY ( socket . setsockopt ( params . level , params . option , user_value , params . value_size ) ) ;
return 0 ;
2020-07-30 21:38:15 +00:00
}
2022-04-01 17:58:27 +00:00
ErrorOr < FlatPtr > Process : : sys $ socketpair ( Userspace < Syscall : : SC_socketpair_params const * > user_params )
2021-04-28 10:39:12 +00:00
{
2022-08-17 20:03:04 +00:00
VERIFY_NO_PROCESS_BIG_LOCK ( this ) ;
2021-09-05 15:51:37 +00:00
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
2021-04-28 10:39:12 +00:00
if ( params . domain ! = AF_LOCAL )
return EINVAL ;
if ( params . protocol ! = 0 & & params . protocol ! = PF_LOCAL )
return EINVAL ;
2021-09-05 13:54:53 +00:00
auto pair = TRY ( LocalSocket : : try_create_connected_pair ( params . type & SOCK_TYPE_MASK ) ) ;
2021-04-28 10:39:12 +00:00
2022-01-29 00:29:07 +00:00
return m_fds . with_exclusive ( [ & ] ( auto & fds ) - > ErrorOr < FlatPtr > {
2022-01-29 00:22:28 +00:00
auto fd_allocation0 = TRY ( fds . allocate ( ) ) ;
auto fd_allocation1 = TRY ( fds . allocate ( ) ) ;
int allocated_fds [ 2 ] ;
allocated_fds [ 0 ] = fd_allocation0 . fd ;
allocated_fds [ 1 ] = fd_allocation1 . fd ;
setup_socket_fd ( fds , allocated_fds [ 0 ] , pair . description0 , params . type ) ;
setup_socket_fd ( fds , allocated_fds [ 1 ] , pair . description1 , params . type ) ;
2023-03-24 08:59:28 +00:00
if ( copy_n_to_user ( params . sv , allocated_fds , 2 ) . is_error ( ) ) {
2022-01-29 00:22:28 +00:00
// Avoid leaking both file descriptors on error.
fds [ allocated_fds [ 0 ] ] = { } ;
fds [ allocated_fds [ 1 ] ] = { } ;
return EFAULT ;
}
return 0 ;
} ) ;
2021-04-28 10:39:12 +00:00
}
2022-01-29 00:22:28 +00:00
2020-07-30 21:38:15 +00:00
}