From 861dd76d7f8664f41ab1deb101885e6b4364f09f Mon Sep 17 00:00:00 2001 From: nmzik Date: Thu, 8 Oct 2026 02:56:29 +0400 Subject: [PATCH] net: accept sufficient Ethernet address output buffers --- src/libs/network.cpp | 16 +++------ src/libs/network.h | 4 ++- tests/KernelFileSystemTests.cpp | 63 +++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/libs/network.cpp b/src/libs/network.cpp index 795d0e05c..a4aac332f 100644 --- a/src/libs/network.cpp +++ b/src/libs/network.cpp @@ -832,10 +832,6 @@ namespace Net { LIB_NAME("Net", "Net"); -struct NetEtherAddr { - uint8_t data[6] = {0}; -}; - #if defined(_WIN32) using NativeSocket = SOCKET; static constexpr NativeSocket INVALID_NATIVE_SOCKET = INVALID_SOCKET; @@ -1564,14 +1560,12 @@ const char* KYTY_SYSV_ABI NetInetNtop(int af, const void* src, char* dst, uint32 int KYTY_SYSV_ABI NetEtherNtostr(const NetEtherAddr* n, char* str, size_t len) { PRINT_NAME(); - NetEtherAddr zero {}; + if (n == nullptr || str == nullptr || len < 18) { + return NET_ERROR_EINVAL; + } - EXIT_NOT_IMPLEMENTED(len != 18); - EXIT_NOT_IMPLEMENTED(n == nullptr); - EXIT_NOT_IMPLEMENTED(str == nullptr); - EXIT_NOT_IMPLEMENTED(memcmp(n->data, zero.data, sizeof(zero.data)) != 0); - - strcpy(str, "00:00:00:00:00:00"); // NOLINT + std::snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x", n->data[0], n->data[1], + n->data[2], n->data[3], n->data[4], n->data[5]); return OK; } diff --git a/src/libs/network.h b/src/libs/network.h index 66a157f36..c00046e1c 100644 --- a/src/libs/network.h +++ b/src/libs/network.h @@ -16,7 +16,9 @@ struct Lifecycle { namespace Net { -struct NetEtherAddr; +struct NetEtherAddr { + uint8_t data[6] = {0}; +}; union NetEpollData { void* ptr; diff --git a/tests/KernelFileSystemTests.cpp b/tests/KernelFileSystemTests.cpp index d676e4e23..9c138726c 100644 --- a/tests/KernelFileSystemTests.cpp +++ b/tests/KernelFileSystemTests.cpp @@ -135,6 +135,35 @@ void TestRandomDevices() { } } +void TestFileDescriptorFlags() { + Loader::SymbolDatabase symbols; + Libs::InitLibKernel_1(&symbols); + const auto* symbol = symbols.Find( + {"8nY19bKoiZk", "Posix", 1, "libkernel", 1, 1, Loader::SymbolType::Func}); + Check(symbol != nullptr, "POSIX fcntl export resolves"); + const auto fcntl = reinterpret_cast(symbol->vaddr); + Check(fcntl(std::numeric_limits::min(), 1, 0) == -1 && + *Libs::Posix::GetErrorAddr() == Libs::Posix::POSIX_EBADF, + "invalid descriptor reports EBADF"); + for (const auto* path : {"/dev/urandom", "/dev/random"}) { + const int fd = FileSystem::KernelOpen(path, 0, 0); + Check(fd >= 3, "open descriptor for flag checks"); + Check(fcntl(fd, 1, 0) == 0 && fcntl(fd, 2, 1) == 0 && fcntl(fd, 1, 0) == 1, + "entropy descriptor retains close-on-exec flag"); + Check(fcntl(fd, 2, 0) == 0 && fcntl(fd, 1, 0) == 0, + "close-on-exec flag can be cleared"); + Check(fcntl(fd, -1, 0) == -1 && *Libs::Posix::GetErrorAddr() == Libs::Posix::POSIX_EINVAL, + "unsupported fcntl command reports EINVAL"); + Check(FileSystem::KernelClose(fd) == OK, "close entropy source"); + Check(fcntl(fd, 1, 0) == -1 && *Libs::Posix::GetErrorAddr() == Libs::Posix::POSIX_EBADF, + "closed descriptor reports EBADF"); + const int cloexec_fd = FileSystem::KernelOpen(path, 0x00100000, 0); + Check(cloexec_fd >= 3 && fcntl(cloexec_fd, 1, 0) == 1, + "O_CLOEXEC sets the descriptor flag on open"); + Check(FileSystem::KernelClose(cloexec_fd) == OK, "close flagged entropy source"); + } +} + void TestSaveOpenVisibility() { constexpr char Path[] = "/savedata0/visible-save.dat"; constexpr char Payload[] = "saved progress"; @@ -1132,6 +1161,38 @@ void CheckSocketReceiveBuffer(int reader, int writer) { } #endif +void CheckEtherAddressFormatting() { + Loader::SymbolDatabase symbols; + Libs::LibNet::InitNet_1_Net(&symbols); + const auto *format_symbol = symbols.FindByNid("v6M4txecCuo", Loader::SymbolType::Func); + const auto *errno_symbol = symbols.FindByNid("HQOwnfMGipQ", Loader::SymbolType::Func); + Check(format_symbol && errno_symbol, "Ethernet formatting and errno exports resolve"); + using Format = int (KYTY_SYSV_ABI *)(const Libs::Network::Net::NetEtherAddr *, char *, size_t); + using Errno = int *(KYTY_SYSV_ABI *)(); + const auto format = reinterpret_cast(format_symbol->vaddr); + auto *net_errno = reinterpret_cast(errno_symbol->vaddr)(); + for (const auto address : {Libs::Network::Net::NetEtherAddr{}, + Libs::Network::Net::NetEtherAddr{{0x01, 0x23, 0x45, 0xab, 0xcd, 0xef}}}) { + const auto *expected = address.data[0] == 0 ? "00:00:00:00:00:00" : "01:23:45:ab:cd:ef"; + for (const size_t size : {18u, 127u}) { + std::array text; + text.fill('!'); + Check(format(&address, text.data(), size) == OK && + std::strcmp(text.data(), expected) == 0 && text[18] == '!', + "Ethernet formatting accepts exact and larger buffers"); + } + } + const Libs::Network::Net::NetEtherAddr address{}; + std::array text; + text.fill('!'); + Check(format(&address, text.data(), 17) == Libs::Network::NET_ERROR_EINVAL && + *net_errno == Libs::Posix::POSIX_EINVAL && + std::all_of(text.begin(), text.end(), [](char c) { return c == '!'; }) && + format(nullptr, text.data(), text.size()) == Libs::Network::NET_ERROR_EINVAL && + format(&address, nullptr, text.size()) == Libs::Network::NET_ERROR_EINVAL, + "Ethernet formatting rejects invalid arguments without writing output"); +} + void CheckSocketWakeup() { namespace Net = Libs::Network::Net; Loader::SymbolDatabase symbols; @@ -1413,6 +1474,7 @@ int main(int, char**) { TempDirectory temporary; FileSystem::Initialize(); TestRandomDevices(); + TestFileDescriptorFlags(); CheckMountRoot(temporary.Path()); CheckUnmappedPaths(temporary.Path()); CheckArchiveMount(temporary.Path()); @@ -1427,6 +1489,7 @@ int main(int, char**) { CheckSaveRename(temporary.Path(), "replacement-save"); FileSystem::Shutdown(); CheckSocketWakeup(); + CheckEtherAddressFormatting(); TestNpWebApi2Memory(); graphics.reset(); subsystems.Destroy();