mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 17:40:27 +00:00
4b2651ddab
The way the Process::FileDescriptions::allocate() API works today means that two callers who allocate back to back without associating a FileDescription with the allocated FD, will receive the same FD and thus one will stomp over the other. Naively tracking which FileDescriptions are allocated and moving onto the next would introduce other bugs however, as now if you "allocate" a fd and then return early further down the control flow of the syscall you would leak that fd. This change modifies this behavior by tracking which descriptions are allocated and then having an RAII type to "deallocate" the fd if the association is not setup the end of it's scope.
68 lines
2 KiB
C++
68 lines
2 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Kernel/FileSystem/FileDescription.h>
|
|
#include <Kernel/Net/LocalSocket.h>
|
|
#include <Kernel/Process.h>
|
|
|
|
namespace Kernel {
|
|
|
|
KResultOr<FlatPtr> Process::sys$sendfd(int sockfd, int fd)
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
|
|
REQUIRE_PROMISE(sendfd);
|
|
auto socket_description = fds().file_description(sockfd);
|
|
if (!socket_description)
|
|
return EBADF;
|
|
if (!socket_description->is_socket())
|
|
return ENOTSOCK;
|
|
auto& socket = *socket_description->socket();
|
|
if (!socket.is_local())
|
|
return EAFNOSUPPORT;
|
|
if (!socket.is_connected())
|
|
return ENOTCONN;
|
|
|
|
auto passing_descriptor = fds().file_description(fd);
|
|
if (!passing_descriptor)
|
|
return EBADF;
|
|
|
|
auto& local_socket = static_cast<LocalSocket&>(socket);
|
|
return local_socket.sendfd(*socket_description, *passing_descriptor);
|
|
}
|
|
|
|
KResultOr<FlatPtr> Process::sys$recvfd(int sockfd, int options)
|
|
{
|
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
|
|
REQUIRE_PROMISE(recvfd);
|
|
auto socket_description = fds().file_description(sockfd);
|
|
if (!socket_description)
|
|
return EBADF;
|
|
if (!socket_description->is_socket())
|
|
return ENOTSOCK;
|
|
auto& socket = *socket_description->socket();
|
|
if (!socket.is_local())
|
|
return EAFNOSUPPORT;
|
|
|
|
auto new_fd_or_error = m_fds.allocate();
|
|
if (new_fd_or_error.is_error())
|
|
return new_fd_or_error.error();
|
|
auto new_fd = new_fd_or_error.release_value();
|
|
|
|
auto& local_socket = static_cast<LocalSocket&>(socket);
|
|
auto received_descriptor_or_error = local_socket.recvfd(*socket_description);
|
|
|
|
if (received_descriptor_or_error.is_error())
|
|
return received_descriptor_or_error.error();
|
|
|
|
u32 fd_flags = 0;
|
|
if (options & O_CLOEXEC)
|
|
fd_flags |= FD_CLOEXEC;
|
|
|
|
m_fds[new_fd.fd].set(*received_descriptor_or_error.value(), fd_flags);
|
|
return new_fd.fd;
|
|
}
|
|
|
|
}
|