mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 00:35:47 +00:00
fix(libkernel): check open flags before the path in open, _open and openat
FreeBSD 11.4 rejects access mode 3 in kern_openat and O_CREAT|O_EXCL|O_DIRECTORY in vn_open_cred before namei reads the path or resolves the directory descriptor. open, _open and openat checked a NULL or empty path first and returned EFAULT or ENOENT for those flags. InvalidOpenFlags moves to FileFlags.hpp and runs first in all three.
This commit is contained in:
1 parent
fd407e34a0
commit
ff688b2146
6 files changed
+21
-7
No files matched your search
@@ -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
|
||||
@@ -173,11 +173,6 @@ static int SceIoErrorFromErrno(int error) {
|
||||
return static_cast<int>(0x80020000u | static_cast<unsigned>(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);
|
||||
|
||||
@@ -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<std::uint16_t>(mode)));
|
||||
}
|
||||
|
||||
@@ -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<int>(Fail(GuestEinval));
|
||||
if (path == nullptr) return static_cast<int>(Fail(GuestEfault));
|
||||
if (*path == '\0') return static_cast<int>(Fail(GuestEnoent));
|
||||
if (fd == GuestAtFdcwd || *path == '/') return open_nid_postfix(path, flags, mode);
|
||||
|
||||
@@ -858,6 +858,10 @@ int main() {
|
||||
Require(sceKernelOpen(invalidFlagsName.c_str(), 0x20a02, 0600) == static_cast<int>(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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user