From 994fb42929b1c602088d2123fdfc81bbf8e62208 Mon Sep 17 00:00:00 2001 From: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:00:11 +0200 Subject: [PATCH] fix(libkernel_sys): check the readlink size before the path FreeBSD 11.4 kern_readlinkat returns EINVAL for a count above IOSIZE_MAX before namei looks at the path. readlink and readlinkat checked a NULL or empty path first, so readlink(NULL, buf, SIZE_MAX) returned EFAULT and readlink("", buf, SIZE_MAX) returned ENOENT where FreeBSD returns EINVAL. Co-Authored-By: Claude Sonnet 5.5 --- core/libs/prx/libkernel_sys/Export.cpp | 4 ++-- core/libs/tests/GuestKernelSys.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libkernel_sys/Export.cpp b/core/libs/prx/libkernel_sys/Export.cpp index a0adb45364..b7e777091a 100644 --- a/core/libs/prx/libkernel_sys/Export.cpp +++ b/core/libs/prx/libkernel_sys/Export.cpp @@ -273,18 +273,18 @@ int APS5_VABI fstatfs_nid_postfix(int d, void* buf) { } std::int64_t APS5_VABI readlink_nid_postfix(const char* path, char* buffer, std::size_t size) { + if (size > static_cast(std::numeric_limits::max())) return Fail(GuestEinval); if (path == nullptr) return Fail(GuestEfault); if (*path == '\0') return Fail(GuestEnoent); - if (size > static_cast(std::numeric_limits::max())) return Fail(GuestEinval); std::filesystem::path native; if (const int error = ResolvePathError_nid_no_patch(path, native)) return Fail(error); return ReadNativeLink(native, buffer, size); } std::int64_t APS5_VABI readlinkat_nid_postfix(int fd, const char* path, char* buffer, std::size_t size) { + if (size > static_cast(std::numeric_limits::max())) return Fail(GuestEinval); if (path == nullptr) return Fail(GuestEfault); if (*path == '\0') return Fail(GuestEnoent); - if (size > static_cast(std::numeric_limits::max())) return Fail(GuestEinval); if (fd == GuestAtFdcwd || *path == '/') return readlink_nid_postfix(path, buffer, size); int error = 0; const char* base = GetDirectoryDescriptorPath_nid_no_patch(fd, &error); diff --git a/core/libs/tests/GuestKernelSys.cpp b/core/libs/tests/GuestKernelSys.cpp index ea71a5644b..16bd6770eb 100644 --- a/core/libs/tests/GuestKernelSys.cpp +++ b/core/libs/tests/GuestKernelSys.cpp @@ -300,6 +300,13 @@ int main() { Require(readlink_nid_postfix((root / "missing").string().c_str(), buffer, sizeof(buffer)) == -1 && Error() == 2); Require(readlink_nid_postfix("", buffer, sizeof(buffer)) == -1 && Error() == 2); Require(readlink_nid_postfix(nullptr, buffer, sizeof(buffer)) == -1 && Error() == 14); + constexpr auto hugeSize = static_cast(-1); + Require(readlink_nid_postfix(nullptr, buffer, hugeSize) == -1 && Error() == 22); + Require(readlink_nid_postfix("", buffer, hugeSize) == -1 && Error() == 22); + Require(readlink_nid_postfix((root / "missing").string().c_str(), buffer, hugeSize) == -1 && Error() == 22); + Require(readlinkat_nid_postfix(-100, nullptr, buffer, hugeSize) == -1 && Error() == 22); + Require(readlinkat_nid_postfix(-100, "", buffer, hugeSize) == -1 && Error() == 22); + Require(readlinkat_nid_postfix(-100, nullptr, buffer, sizeof(buffer)) == -1 && Error() == 14); #ifndef _WIN32 Require(readlink_nid_postfix((root / std::string(300, 'n')).string().c_str(), buffer, sizeof(buffer)) == -1 && Error() == 63); #endif