From eb9da23e6804c11baa01473574375e9b51217bcd Mon Sep 17 00:00:00 2001 From: milescoviello Date: Mon, 12 Oct 2026 13:38:30 +0000 Subject: [PATCH] fix(libkernel): accept socket option values longer than an int setsockopt() on a guest socket failed with EINVAL unless the option length was exactly sizeof(int), so an option passed as a 64-bit value (for example SO_BROADCAST or SO_RCVBUF from an int64_t or size_t) was rejected and silently left unchanged. FreeBSD 11.4 reads these integer options through sooptcopyin() with the size of an int as both the wanted and the minimum length, and only a shorter value fails. sys/kern/uipc_socket.c, sooptcopyin(): * If the user gives us more than we wanted, we ignore it, but if we * don't get the minimum length the caller wants, we return EINVAL. ... if ((valsize = sopt->sopt_valsize) < minlen) return EINVAL; if (valsize > len) sopt->sopt_valsize = valsize = len; and sosetopt() uses it for SO_BROADCAST, SO_REUSEADDR, SO_SNDBUF and SO_RCVBUF: error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); A longer value now sets the option from its first int; a shorter one still fails with EINVAL. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libkernel/Socket/src/Udp.cpp | 2 +- core/libs/tests/GuestUdp.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libkernel/Socket/src/Udp.cpp b/core/libs/prx/libkernel/Socket/src/Udp.cpp index 8787a302f..ba7cac5a6 100644 --- a/core/libs/prx/libkernel/Socket/src/Udp.cpp +++ b/core/libs/prx/libkernel/Socket/src/Udp.cpp @@ -503,7 +503,7 @@ int APS5_VABI setsockopt_nid_postfix(int descriptor, int level, int option, if (!socket) return -1; const int nativeOption = Option(option); if (level != 0xffff || nativeOption == -1) return Fail(42); - if (!value || length != sizeof(int)) return Fail(22); + if (!value || length < sizeof(int)) return Fail(22); return ::setsockopt(socket->value, SOL_SOCKET, nativeOption, static_cast(value), sizeof(int)) ? Fail(NativeError()) : 0; } diff --git a/core/libs/tests/GuestUdp.cpp b/core/libs/tests/GuestUdp.cpp index 5b4dc2694..32628ba8d 100644 --- a/core/libs/tests/GuestUdp.cpp +++ b/core/libs/tests/GuestUdp.cpp @@ -122,6 +122,12 @@ int main() { int option = 0; std::uint32_t optionSize = sizeof(option); Require(getsockopt_nid_postfix(sender, 0xffff, 0x20, &option, &optionSize) == 0 && option != 0); + for (const std::int64_t wide : {0, 1}) { + Require(setsockopt_nid_postfix(sender, 0xffff, 0x20, &wide, sizeof(wide)) == 0); + optionSize = sizeof(option); + Require(getsockopt_nid_postfix(sender, 0xffff, 0x20, &option, &optionSize) == 0 && (option != 0) == (wide != 0)); + } + Require(setsockopt_nid_postfix(sender, 0xffff, 0x20, &enabled, 2) == -1 && *__error_nid_postfix() == 22); Require(setsockopt_nid_postfix(sender, 0xffff, 12345, &enabled, sizeof(enabled)) == -1); Require(*__error_nid_postfix() == 42); const int unconnected = socket_nid_postfix(2, 2, 0);