From d26c9bcabcce22678d3bbd2a7e14b52fc7ab23f1 Mon Sep 17 00:00:00 2001 From: MarcZX100 Date: Sun, 11 Oct 2026 11:00:35 +0000 Subject: [PATCH] fix(libkernel): reject empty filesystem paths --- core/libs/prx/libkernel/File/src/Open.cpp | 2 ++ core/libs/prx/libkernel/File/src/Stdio.cpp | 6 ++++++ core/libs/tests/GuestFilesystem.cpp | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp index ebdc6c064..2da21d76d 100644 --- a/core/libs/prx/libkernel/File/src/Open.cpp +++ b/core/libs/prx/libkernel/File/src/Open.cpp @@ -226,6 +226,7 @@ int APS5_VABI sceKernelStat(const char* path, FileStat* sb) { if (sb == nullptr) { throw std::invalid_argument(std::string(__func__) + ": sb is null"); } + if (*path == '\0') return SceErrorFromErrno(2); std::filesystem::path native; try { native = ResolvePath_nid_no_patch(path); @@ -249,6 +250,7 @@ int APS5_VABI sceKernelUnlink(const char* path) { if (path == nullptr) { throw std::invalid_argument(std::string(__func__) + ": path is null"); } + if (*path == '\0') return SceErrorFromErrno(2); auto native = ResolvePath_nid_no_patch(path); constexpr int GuestEperm = 1; std::error_code error; diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 7fbef5c28..026b5682f 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -696,6 +696,7 @@ int APS5_VABI unlink_nid_postfix(const char* path) { int APS5_VABI sceKernelCheckReachability(const char* path) { if (path == nullptr) return SCE_KERNEL_ERROR_EINVAL; + if (*path == '\0') return SCE_KERNEL_ERROR_ENOENT; if (std::strlen(path) > 255) return SCE_KERNEL_ERROR_ENAMETOOLONG; std::error_code error; return std::filesystem::exists(ResolvePath_nid_no_patch(path), error) ? 0 : SCE_KERNEL_ERROR_ENOENT; @@ -999,6 +1000,7 @@ int64_t APS5_VABI pwritev_nid_postfix(int d, const KernelIovec* iov, int iovcnt, int APS5_VABI sceKernelRename(const char* from, const char* to) { if (from == nullptr || to == nullptr) throw std::invalid_argument("sceKernelRename: path is null"); + if (*from == '\0' || *to == '\0') return SceErrorFromErrno(GUEST_ENOENT); const auto source = ResolvePath_nid_no_patch(from); std::error_code error; if (!std::filesystem::exists(source, error)) return SceErrorFromErrno(GUEST_ENOENT); @@ -1012,6 +1014,7 @@ int APS5_VABI sceKernelRename(const char* from, const char* to) { int APS5_VABI sceKernelRmdir(const char* path) { if (path == nullptr) throw std::invalid_argument("sceKernelRmdir: path is null"); + if (*path == '\0') return SceErrorFromErrno(GUEST_ENOENT); const auto native = ResolvePath_nid_no_patch(path); std::error_code error; if (!std::filesystem::is_directory(native, error)) { @@ -1035,6 +1038,7 @@ extern "C" { int APS5_VABI sceKernelChmod_nid_postfix(const char* path, std::uint16_t mode) { if (!path) return SceErrorFromErrno(GUEST_EFAULT); + if (!*path) return SceErrorFromErrno(GUEST_ENOENT); const auto native = ResolvePath_nid_no_patch(path); if (NativeChmod(native, mode & 07777) != 0) return SceErrorFromErrno(errno); return 0; @@ -1052,6 +1056,7 @@ int APS5_VABI fchmod_nid_postfix(int d, int mode) { int APS5_VABI sceKernelTruncate_nid_postfix(const char* path, std::int64_t length) { if (path == nullptr) throw std::invalid_argument("sceKernelTruncate: path is null"); + if (*path == '\0') return SceErrorFromErrno(GUEST_ENOENT); if (length < 0) return SceErrorFromErrno(GUEST_EINVAL); const auto native = ResolvePath_nid_no_patch(path); std::error_code error; @@ -1070,6 +1075,7 @@ int APS5_VABI truncate_nid_postfix(const char* path, std::int64_t length) { int APS5_VABI sceKernelUtimes_nid_postfix(const char* path, const KernelTimeval* times) { if (path == nullptr) throw std::invalid_argument("sceKernelUtimes: path is null"); + if (*path == '\0') return SceErrorFromErrno(GUEST_ENOENT); if (times != nullptr) { for (int i = 0; i < 2; ++i) { if (times[i].tv_usec < 0 || times[i].tv_usec >= 1000000) return SCE_KERNEL_ERROR_EINVAL; diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index 4f2710df7..8f734df03 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -45,8 +45,10 @@ int APS5_VABI mkdir_nid_postfix(const char*, unsigned short); int APS5_VABI sceKernelOpen(const char*, int, unsigned short); int APS5_VABI sceKernelClose(int); int APS5_VABI sceKernelStat(const char*, FileStat*); +int APS5_VABI sceKernelCheckReachability(const char*); int APS5_VABI sceKernelFstat(int, FileStat*); int APS5_VABI sceKernelUnlink(const char*); +int APS5_VABI sceKernelRename(const char*, const char*); int APS5_VABI sceKernelRmdir(const char*); int APS5_VABI sceKernelMkdir(const char*, unsigned short); int* APS5_VABI __error_nid_postfix(); @@ -77,6 +79,7 @@ static void Check(bool value, int line) { int main() { Require(chmod_nid_postfix(nullptr, 0600) == -1 && *__error_nid_postfix() == 14); Require(sceKernelChmod_nid_postfix(nullptr, 0600) == static_cast(0x8002000eu)); + Require(chmod_nid_postfix("", 0600) == -1 && *__error_nid_postfix() == 2); Require(chmod_nid_postfix("anyps5_missing_chmod_path", 0600) == -1 && *__error_nid_postfix() == 2); Require(sceKernelChmod_nid_postfix("anyps5_missing_chmod_path", 0600) == static_cast(0x80020002u)); Require(sceKernelDebugOutText(-1, "text") == static_cast(0x80020016u)); @@ -267,6 +270,21 @@ int main() { const auto rootName = root.string(); { std::ofstream stream(present); stream << "posix"; } FileStat status{}; + Require(sceKernelStat("", &status) == static_cast(0x80020002u)); + Require(sceKernelCheckReachability("") == static_cast(0x80020002u)); + Require(sceKernelRename("", presentName.c_str()) == static_cast(0x80020002u)); + Require(sceKernelRename(presentName.c_str(), "") == static_cast(0x80020002u)); + Require(sceKernelRmdir("") == static_cast(0x80020002u)); + Require(sceKernelMkdir("", 0700) == static_cast(0x80020002u)); + const auto cwdPermissions = std::filesystem::status(".").permissions(); + Require(sceKernelChmod_nid_postfix("", static_cast(cwdPermissions) & 07777) == static_cast(0x80020002u)); + Require(sceKernelTruncate_nid_postfix("", 0) == static_cast(0x80020002u)); + const auto cwdWriteTime = std::filesystem::last_write_time("."); + const int emptyUtimes = sceKernelUtimes_nid_postfix("", nullptr); + std::error_code restoreTimeError; + std::filesystem::last_write_time(".", cwdWriteTime, restoreTimeError); + Require(!restoreTimeError); + Require(emptyUtimes == static_cast(0x80020002u)); Require(stat_nid_postfix(presentName.c_str(), &status) == 0 && status.st_size == 5); Require(stat_nid_postfix(missingName.c_str(), &status) == -1 && *__error_nid_postfix() == 2); Require(sceKernelStat(missingName.c_str(), &status) == static_cast(0x80020002u)); @@ -478,6 +496,7 @@ int main() { Require(rmdir_nid_postfix(nullptr) == -1 && *__error_nid_postfix() == 14); Require(unlink_nid_postfix(missingName.c_str()) == -1 && *__error_nid_postfix() == 2); Require(sceKernelUnlink(missingName.c_str()) == static_cast(0x80020002u)); + Require(sceKernelUnlink("") == static_cast(0x80020002u)); Require(unlink_nid_postfix("") == -1 && *__error_nid_postfix() == 2); Require(unlink_nid_postfix(nullptr) == -1 && *__error_nid_postfix() == 14); Require(unlink_nid_postfix(rootName.c_str()) == -1 && *__error_nid_postfix() == 1 && std::filesystem::is_directory(root));