diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp index 9760bbe879b..8721a364f73 100644 --- a/core/libs/prx/libkernel/File/src/Open.cpp +++ b/core/libs/prx/libkernel/File/src/Open.cpp @@ -173,6 +173,11 @@ 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) { @@ -211,6 +216,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 (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)) { @@ -227,6 +233,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; int error = 0; const char* base = GetDirectoryDescriptorPath_nid_no_patch(directory, &error); if (base == nullptr) return SceErrorFromErrno(error); diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index b87cf1344c6..796d213c711 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -850,6 +850,15 @@ int main() { Require(sceKernelOpen(presentName.c_str(), 0x20402, 0) == static_cast(0x80020014u)); Require(std::filesystem::file_size(present) == 5); Require(sceKernelOpen(missingName.c_str(), 0x20000, 0) == static_cast(0x80020002u)); + const auto invalidFlagsName = (root / "invalid-flags.txt").string(); + Require(sceKernelOpen(presentName.c_str(), 3, 0) == static_cast(0x80020016u)); + Require(sceKernelOpen(missingName.c_str(), 0x203, 0600) == static_cast(0x80020016u)); + Require(open_nid_postfix(presentName.c_str(), 3, 0) == -1 && *__error_nid_postfix() == 22); + Require(_open_nid_postfix(presentName.c_str(), 0x403) == -1 && *__error_nid_postfix() == 22); + 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(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); Require(sceKernelOpen("", 0, 0) == static_cast(0x80020002u)); diff --git a/core/libs/tests/GuestKernelSys.cpp b/core/libs/tests/GuestKernelSys.cpp index d16ff6789ad..e557b1a1cc9 100644 --- a/core/libs/tests/GuestKernelSys.cpp +++ b/core/libs/tests/GuestKernelSys.cpp @@ -323,6 +323,8 @@ int main() { Require(sceKernelClose(made) == 0); Require(openat_nid_postfix(base, "made.bin", SCE_KERNEL_O_WRONLY | SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL, 0644) == -1 && Error() == 17); 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); 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);