diff options
Diffstat (limited to 'src/core/hle/service/sockets')
| -rw-r--r-- | src/core/hle/service/sockets/bsd.cpp | 46 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/bsd.h | 2 |
2 files changed, 29 insertions, 19 deletions
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index e6d23b7bf6..730a7edcc1 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -965,24 +965,24 @@ std::pair<s32, Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> } Errno BSD_USA::CloseImpl(s32 fd) { - const auto descriptor = CopyDescriptor(fd); - if (!descriptor) { - return Errno::BADF; - } - - const Errno bsd_errno = Translate(descriptor->socket->Close()); - if (bsd_errno != Errno::SUCCESS) { - return bsd_errno; + std::shared_ptr<Network::SocketBase> socket; + { + // Free the slot first, so of two threads closing the same fd only one closes the socket. + // Like POSIX close(), the fd is released even if closing the socket fails. + std::scoped_lock lock{file_descriptors_mutex}; + if (!IsFileDescriptorValid(fd)) { + return Errno::BADF; + } + if (!file_descriptors[fd]->socket) { + LOG_WARNING(Service, "Uninitialized socket"); + return Errno::BADF; + } + socket = std::move(file_descriptors[fd]->socket); + file_descriptors[fd].reset(); } LOG_INFO(Service, "Close socket fd={}", fd); - - // Another thread may have closed this fd and reused the slot meanwhile - std::scoped_lock lock{file_descriptors_mutex}; - if (file_descriptors[fd] && file_descriptors[fd]->socket == descriptor->socket) { - file_descriptors[fd].reset(); - } - return bsd_errno; + return Translate(socket->Close()); } std::variant<s32, Errno> BSD_USA::DuplicateSocketImpl(s32 fd) { @@ -1070,7 +1070,8 @@ void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) { // Runs on the room thread. The copies keep each socket alive if a bsd thread closes it, so - // the bsd threads do not wait for the decompression below. + // the bsd threads do not wait for the decompression below. Only sockets that accept the + // packet are collected, so an unwanted packet is never decompressed. std::array<std::shared_ptr<Network::SocketBase>, MAX_FD> sockets{}; size_t num_sockets = 0; { @@ -1081,7 +1082,8 @@ void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) { } // A duplicated fd shares its socket, which must still get each packet only once const auto sockets_end = sockets.begin() + num_sockets; - if (std::find(sockets.begin(), sockets_end, descriptor->socket) == sockets_end) { + if (std::find(sockets.begin(), sockets_end, descriptor->socket) == sockets_end && + descriptor->socket->AcceptsProxyPacket(packet)) { sockets[num_sockets++] = descriptor->socket; } } @@ -1090,13 +1092,19 @@ void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) { return; } - // Decompress once for all sockets that share the port + // Decompress once for all sockets that share the port. The room does not check the frame, so + // drop a malformed or oversized one instead of throwing on the room thread. + auto data = Common::Compression::TryDecompressDataZSTD(packet.data, MAX_ROOM_PACKET_SIZE); + if (!data) { + LOG_WARNING(Service, "Dropped a room packet with an invalid or oversized payload"); + return; + } const Network::ProxyPacket decompressed{ .local_endpoint = packet.local_endpoint, .remote_endpoint = packet.remote_endpoint, .protocol = packet.protocol, .broadcast = packet.broadcast, - .data = Common::Compression::DecompressDataZSTD(packet.data), + .data = std::move(*data), }; for (size_t i = 0; i < num_sockets; ++i) { sockets[i]->HandleProxyPacket(decompressed); diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 559830d7a1..bff80d7c00 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -44,6 +44,8 @@ public: private: /// Maximum number of file descriptors static constexpr size_t MAX_FD = 128; + /// Largest decompressed room packet. A UDP datagram cannot be larger. + static constexpr size_t MAX_ROOM_PACKET_SIZE = 0x10000; struct FileDescriptor { std::shared_ptr<Network::SocketBase> socket; |
