diff --git a/core/libs/prx/libkernel/File/include/FileFlags.hpp b/core/libs/prx/libkernel/File/include/FileFlags.hpp index 2423ccdacf..374abfc4c5 100644 --- a/core/libs/prx/libkernel/File/include/FileFlags.hpp +++ b/core/libs/prx/libkernel/File/include/FileFlags.hpp @@ -19,4 +19,13 @@ constexpr std::int32_t SCE_KERNEL_O_NONBLOCK = 0x00000004; constexpr std::int32_t SCE_KERNEL_O_DIRECT = 0x00010000; constexpr std::int32_t SCE_KERNEL_O_DIRECTORY = 0x00020000; +namespace File { + +constexpr bool InvalidOpenFlags(std::int32_t flags) { + constexpr std::int32_t createExclusiveDirectory = SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL | SCE_KERNEL_O_DIRECTORY; + return (flags & SCE_KERNEL_O_ACCMODE) == SCE_KERNEL_O_ACCMODE || (flags & createExclusiveDirectory) == createExclusiveDirectory; +} + +} + #endif diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp index 8721a364f7..04beb97dd5 100644 --- a/core/libs/prx/libkernel/File/src/Open.cpp +++ b/core/libs/prx/libkernel/File/src/Open.cpp @@ -173,11 +173,6 @@ static int SceIoErrorFromErrno(int error) { return static_cast(0x80020000u | static_cast(guest)); } -static bool InvalidOpenFlags(int flags) { - constexpr int createExclusiveDirectory = SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL | SCE_KERNEL_O_DIRECTORY; - return (flags & SCE_KERNEL_O_ACCMODE) == SCE_KERNEL_O_ACCMODE || (flags & createExclusiveDirectory) == createExclusiveDirectory; -} - static int OpenNative(const std::filesystem::path& native, int flags, std::uint16_t mode) { #ifdef _WIN32 if ((flags & (SCE_KERNEL_O_DIRECTORY | SCE_KERNEL_O_CREAT)) == SCE_KERNEL_O_DIRECTORY) { @@ -216,7 +211,7 @@ static int OpenNative(const std::filesystem::path& native, int flags, std::uint1 extern "C" { int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode) { - if (InvalidOpenFlags(flags)) return SCE_KERNEL_ERROR_EINVAL; + if (File::InvalidOpenFlags(flags)) return SCE_KERNEL_ERROR_EINVAL; if (path != nullptr && *path == '\0') return SCE_KERNEL_ERROR_ENOENT; APS5_LOG_OUT("path=%s flags=0x%X nativeFlags=0x%X mode=0%o", path, flags, MapFlags(flags), mode); if (path != nullptr && File::IsRandomDevicePath(path)) { @@ -233,7 +228,7 @@ int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode) { } int OpenInDirectory_nid_no_patch(int directory, const char* path, int flags, std::uint16_t mode) { - if (InvalidOpenFlags(flags)) return SCE_KERNEL_ERROR_EINVAL; + if (File::InvalidOpenFlags(flags)) return SCE_KERNEL_ERROR_EINVAL; int error = 0; const char* base = GetDirectoryDescriptorPath_nid_no_patch(directory, &error); if (base == nullptr) return SceErrorFromErrno(error); diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 5ded00a7ba..5ecb117239 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -778,6 +778,7 @@ int APS5_VABI mkdir_nid_postfix(const char* path, uint16_t mode) { } int APS5_VABI open_nid_postfix(const char* path, int flags, int mode) { + if (File::InvalidOpenFlags(flags)) return PosixFailure(GUEST_EINVAL); if (const int error = PathError(path)) return PosixFailure(error); return PosixResult(sceKernelOpen(path, flags, static_cast(mode))); } diff --git a/core/libs/prx/libkernel_sys/Export.cpp b/core/libs/prx/libkernel_sys/Export.cpp index 99809d6212..f2c7c888f7 100644 --- a/core/libs/prx/libkernel_sys/Export.cpp +++ b/core/libs/prx/libkernel_sys/Export.cpp @@ -424,6 +424,7 @@ int APS5_VABI openat_nid_postfix(int fd, const char* path, int flags, ...) { va_end(arguments); #endif } + if (File::InvalidOpenFlags(flags)) return static_cast(Fail(GuestEinval)); if (path == nullptr) return static_cast(Fail(GuestEfault)); if (*path == '\0') return static_cast(Fail(GuestEnoent)); if (fd == GuestAtFdcwd || *path == '/') return open_nid_postfix(path, flags, mode); diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index 796d213c71..6225846e87 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -858,6 +858,10 @@ int main() { Require(sceKernelOpen(invalidFlagsName.c_str(), 0x20a02, 0600) == static_cast(0x80020016u)); Require(open_nid_postfix(invalidFlagsName.c_str(), 0x20a00, 0600) == -1 && *__error_nid_postfix() == 22); Require(!std::filesystem::exists(invalidFlagsName)); + Require(open_nid_postfix(nullptr, 3, 0) == -1 && *__error_nid_postfix() == 22); + Require(open_nid_postfix("", 0x20a00, 0600) == -1 && *__error_nid_postfix() == 22); + Require(_open_nid_postfix(nullptr, 0x403) == -1 && *__error_nid_postfix() == 22); + Require(_open_nid_postfix("", 3) == -1 && *__error_nid_postfix() == 22); Require(std::filesystem::file_size(present) == 5); Require(open_nid_postfix("", 0, 0) == -1 && *__error_nid_postfix() == 2); Require(_open_nid_postfix("", 0) == -1 && *__error_nid_postfix() == 2); diff --git a/core/libs/tests/GuestKernelSys.cpp b/core/libs/tests/GuestKernelSys.cpp index e557b1a1cc..a7e4532a36 100644 --- a/core/libs/tests/GuestKernelSys.cpp +++ b/core/libs/tests/GuestKernelSys.cpp @@ -325,6 +325,10 @@ int main() { Require(openat_nid_postfix(base, "missing.bin", SCE_KERNEL_O_RDONLY) == -1 && Error() == 2); Require(openat_nid_postfix(base, "file.txt", SCE_KERNEL_O_ACCMODE) == -1 && Error() == 22); Require(openat_nid_postfix(base, "absent.bin", SCE_KERNEL_O_WRONLY | SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL | SCE_KERNEL_O_DIRECTORY, 0644) == -1 && Error() == 22); + Require(openat_nid_postfix(base, nullptr, SCE_KERNEL_O_ACCMODE) == -1 && Error() == 22); + Require(openat_nid_postfix(base, "", SCE_KERNEL_O_ACCMODE) == -1 && Error() == 22); + Require(openat_nid_postfix(9999, "", SCE_KERNEL_O_WRONLY | SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL | SCE_KERNEL_O_DIRECTORY, 0644) == -1 && Error() == 22); + Require(openat_nid_postfix(-100, nullptr, SCE_KERNEL_O_ACCMODE) == -1 && Error() == 22); const auto guestFile = "/" + root.filename().string() + "/file.txt"; const int absolute = openat_nid_postfix(-1, guestFile.c_str(), SCE_KERNEL_O_RDONLY); Require(absolute >= 0 && sceKernelClose(absolute) == 0);