From 0b927d171c6d918a675c25f57b2bc0121b7f889d Mon Sep 17 00:00:00 2001 From: cirakg Date: Tue, 3 Nov 2026 01:39:54 +0100 Subject: network: close each bsd fd once and drop unwanted or malformed room packets Two threads closing the same fd both copied the descriptor and both called Close(), so a host socket could be closed twice, and the second closesocket could hit an unrelated socket that had reused the host fd. CloseImpl now frees the slot under file_descriptors_mutex first and only that thread closes the socket; the other gets EBADF. OnProxyPacketReceived decompressed every room packet when any fd had a socket, including native sockets and proxy sockets on other ports. Sockets now report through AcceptsProxyPacket whether they want a packet, and only those are collected, so an unwanted packet is not decompressed. DecompressDataZSTD passed the frame's declared size straight to the vector constructor, so a malformed or unsized frame from a room member threw on the room thread. The new TryDecompressDataZSTD rejects invalid, unsized and oversized frames, and bsd drops such packets with a warning. DecompressDataZSTD now returns an empty vector for them instead of throwing. Assisted-by: Claude Opus 5.5 (investigation and implementation) --- src/common/zstd_compression.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src/common/zstd_compression.cpp') diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp index 7665482ee6..9bb8d7b919 100644 --- a/src/common/zstd_compression.cpp +++ b/src/common/zstd_compression.cpp @@ -35,16 +35,26 @@ std::vector CompressDataZSTDDefault(const u8* source, std::size_t source_siz } std::vector DecompressDataZSTD(std::span compressed) { - const std::size_t decompressed_size = + return TryDecompressDataZSTD(compressed, std::vector{}.max_size()) + .value_or(std::vector{}); +} + +std::optional> TryDecompressDataZSTD(std::span compressed, + std::size_t max_size) { + // The size comes from the frame header, so check it before allocating + const unsigned long long decompressed_size = ZSTD_getFrameContentSize(compressed.data(), compressed.size()); - std::vector decompressed(decompressed_size); + if (decompressed_size == ZSTD_CONTENTSIZE_ERROR || + decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN || decompressed_size > max_size) { + return std::nullopt; + } + std::vector decompressed(static_cast(decompressed_size)); const std::size_t uncompressed_result_size = ZSTD_decompress( decompressed.data(), decompressed.size(), compressed.data(), compressed.size()); - if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) { - // Decompression failed - return {}; + if (ZSTD_isError(uncompressed_result_size) || uncompressed_result_size != decompressed_size) { + return std::nullopt; } return decompressed; } -- cgit v1.2.3