mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #10524 from YossiYad/feat/kernel-sys-console-identity
feat(libkernel_sys): implement sceKernelIsCEX, sceKernelIsDevKit, get_authinfo and sceKernelGetOpenPsIdForSystem
This commit is contained in:
6 files changed
+113
-22
No files matched your search
@@ -269,6 +269,15 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(guest_kernel_sys_sdk_version PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
|
||||
endif()
|
||||
add_test_executable(guest_kernel_sys_console_identity_tests tests/GuestKernelSysConsoleIdentity.cpp)
|
||||
target_include_directories(guest_kernel_sys_console_identity_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_kernel_sys_console_identity_tests PRIVATE libkernel_sys libkernel libc)
|
||||
configure_windows_unwind(guest_kernel_sys_console_identity_tests)
|
||||
add_test(NAME guest_kernel_sys_console_identity COMMAND guest_kernel_sys_console_identity_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_kernel_sys_console_identity PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
|
||||
endif()
|
||||
add_test_executable(nid_buffer_validation_tests nid/tests/BufferValidation.cpp)
|
||||
target_include_directories(nid_buffer_validation_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nid/include)
|
||||
target_compile_features(nid_buffer_validation_tests PRIVATE cxx_std_20)
|
||||
|
||||
@@ -69,11 +69,6 @@ int APS5_VABI futimesat_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI get_authinfo_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI get_module_info_list_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -979,11 +974,6 @@ int APS5_VABI sceKernelGetMemoryPstate(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelGetOpenPsIdForSystem(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelGetPagingStatsOfAllObjects(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -1405,21 +1395,11 @@ int APS5_VABI sceKernelIsAuthenticNeo(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsCEX(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsDebuggerAttached(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsDevKit(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsExperimentalBeta(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -62,6 +62,7 @@ static int GuestFstat(int fd, bool* withoutVnode = nullptr) {
|
||||
|
||||
constexpr int GuestEnoent = 2;
|
||||
constexpr int GuestEperm = 1;
|
||||
constexpr int GuestEsrch = 3;
|
||||
constexpr int GuestEio = 5;
|
||||
constexpr int GuestEbadf = 9;
|
||||
constexpr int GuestEfault = 14;
|
||||
@@ -337,6 +338,27 @@ std::uint16_t APS5_VABI umask_nid_postfix(std::uint16_t mask) {
|
||||
return File::ExchangeCreationMask_nid_no_patch(mask);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelGetOpenPsIdForSystem(void* id) {
|
||||
if (id == nullptr) return GuestEinval;
|
||||
return sceKernelGetOpenPsId(id);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsCEX(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsDevKit(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI get_authinfo_nid_postfix(int pid, KernelAuthInfo* info) {
|
||||
if (info == nullptr) return static_cast<int>(Fail(GuestEperm));
|
||||
if (pid != 0 && pid != getpid_nid_postfix()) return static_cast<int>(Fail(GuestEsrch));
|
||||
*info = {};
|
||||
info->capabilities[0] = 0x2000000000000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI fstatfs_nid_postfix(int d, KernelStatfs* buf) {
|
||||
return _fstatfs_nid_postfix(d, buf);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,14 @@ struct KernelTitleWorkaround {
|
||||
std::uint64_t ids[2];
|
||||
};
|
||||
|
||||
struct KernelAuthInfo {
|
||||
std::uint64_t programAuthorityId;
|
||||
std::uint64_t capabilities[4];
|
||||
std::uint64_t attributes[4];
|
||||
std::uint64_t credentials[8];
|
||||
};
|
||||
static_assert(sizeof(KernelAuthInfo) == 0x88);
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI aio_read_nid_postfix(GuestAiocb* aiocb);
|
||||
@@ -81,7 +89,7 @@ int APS5_VABI cpuset_getid_nid_postfix(void);
|
||||
int APS5_VABI cpuset_setid_nid_postfix(void);
|
||||
int APS5_VABI dynlib_get_obj_member_nid_postfix(void);
|
||||
int APS5_VABI futimesat_nid_postfix(void);
|
||||
int APS5_VABI get_authinfo_nid_postfix(void);
|
||||
int APS5_VABI get_authinfo_nid_postfix(int pid, KernelAuthInfo* info);
|
||||
int APS5_VABI get_module_info_list_nid_postfix(void);
|
||||
int APS5_VABI get_page_table_stats_nid_postfix(void);
|
||||
int APS5_VABI get_sdk_compiled_version_nid_postfix(void);
|
||||
@@ -265,7 +273,7 @@ int APS5_VABI sceKernelGetIpcPath(void);
|
||||
int APS5_VABI sceKernelGetKnobs(void);
|
||||
int APS5_VABI sceKernelGetKqueueFromEqueue(void);
|
||||
int APS5_VABI sceKernelGetMemoryPstate(void);
|
||||
int APS5_VABI sceKernelGetOpenPsIdForSystem(void);
|
||||
int APS5_VABI sceKernelGetOpenPsIdForSystem(void* id);
|
||||
int APS5_VABI sceKernelGetPagingStatsOfAllObjects(void);
|
||||
int APS5_VABI sceKernelGetPagingStatsOfAllThreads(void);
|
||||
int APS5_VABI sceKernelGetParentApp(void);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "prx/libkernel_sys/libkernel_sys.hpp"
|
||||
#include "prx/libc/libc.hpp"
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int GuestEperm = 1;
|
||||
constexpr int GuestEsrch = 3;
|
||||
|
||||
void Require(bool condition, const char* message) {
|
||||
if (!condition) {
|
||||
std::fprintf(stderr, "KERNEL SYS CONSOLE IDENTITY: %s\n", message);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckConsoleKind() {
|
||||
Require(sceKernelIsCEX() == 1, "the console must be reported as a retail unit");
|
||||
Require(sceKernelIsDevKit() == 0, "the console must not be reported as a development kit");
|
||||
}
|
||||
|
||||
void CheckAuthInfo() {
|
||||
struct {
|
||||
KernelAuthInfo value;
|
||||
std::uint64_t guard;
|
||||
} info;
|
||||
*__error_nid_postfix() = 0;
|
||||
Require(get_authinfo_nid_postfix(0, nullptr) == -1 && *__error_nid_postfix() == GuestEperm, "a null result must fail with EPERM");
|
||||
std::memset(&info, 0x5a, sizeof(info));
|
||||
*__error_nid_postfix() = 0;
|
||||
Require(get_authinfo_nid_postfix(getpid_nid_postfix() + 1, &info.value) == -1 && *__error_nid_postfix() == GuestEsrch,
|
||||
"another process must fail with ESRCH");
|
||||
for (const auto byte : std::bit_cast<std::array<std::uint8_t, sizeof(info)>>(info))
|
||||
Require(byte == 0x5a, "a refused call must not write the result");
|
||||
for (const int pid : {0, getpid_nid_postfix()}) {
|
||||
std::memset(&info, 0x5a, sizeof(info));
|
||||
Require(get_authinfo_nid_postfix(pid, &info.value) == 0, "the guest process must be described");
|
||||
Require(info.value.programAuthorityId == 0 && info.value.capabilities[0] == 0x2000000000000000, "the authority ID or first capability word is wrong");
|
||||
const auto bytes = std::bit_cast<std::array<std::uint8_t, sizeof(KernelAuthInfo)>>(info.value);
|
||||
for (std::size_t i = 16; i < bytes.size(); ++i) Require(bytes[i] == 0, "the rest of the result must be cleared");
|
||||
Require(info.guard == 0x5a5a5a5a5a5a5a5a, "get_authinfo wrote past its 0x88-byte result");
|
||||
}
|
||||
}
|
||||
|
||||
void CheckOpenPsId() {
|
||||
std::array<std::uint8_t, 16> plain{};
|
||||
std::array<std::uint8_t, 24> system;
|
||||
system.fill(0xa5);
|
||||
*__error_nid_postfix() = GuestEsrch;
|
||||
Require(sceKernelGetOpenPsIdForSystem(nullptr) == 22, "a null system OpenPSID must return positive EINVAL");
|
||||
Require(*__error_nid_postfix() == GuestEsrch, "a null system OpenPSID must leave errno unchanged");
|
||||
for (auto byte : system) Require(byte == 0xa5, "a null system OpenPSID must not write output");
|
||||
Require(sceKernelGetOpenPsId(plain.data()) == 0, "the OpenPSID must be readable");
|
||||
Require(sceKernelGetOpenPsIdForSystem(system.data()) == 0, "the system OpenPSID must be readable");
|
||||
Require(std::memcmp(plain.data(), system.data(), plain.size()) == 0, "both OpenPSID queries must agree");
|
||||
for (std::size_t i = plain.size(); i < system.size(); ++i) Require(system[i] == 0xa5, "the system OpenPSID wrote past 16 bytes");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckConsoleKind();
|
||||
CheckAuthInfo();
|
||||
CheckOpenPsId();
|
||||
return 0;
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
- [fork](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) throws: creating a child process is not supported. PPSA19111 imports it and fails to load without it. Its engine calls `fork` in `Posix_Daemonize`, only with `-daemonize`, and in `Platform_ShellExecute` before `execvp("xdg-open")`, which the main menu's Previews button reaches, so pressing Previews ends in this throw. [setsid](../../../core/libs/prx/libkernel_sys/Export.cpp) fails with `EPERM`, as FreeBSD's does for a process group leader, since the guest is taken to lead its own process group (see `kill`). [umask](../../../core/libs/prx/libkernel_sys/Export.cpp) keeps the guest's mask (initially 022, masked to 07777) and returns the previous one, Linux named shared-memory creation applies it, but ordinary files are still created with the host process's mask
|
||||
- [sceKernelGetModuleInfoInternal and sceKernelGetModuleListInternal](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) answer for every loaded module, system modules included. `sceKernelGetModuleInfoInternal` fills the 0x1A8-byte `SceKernelModuleInfoEx` of a module handle the way `sceKernelGetModuleInfoFromAddr` does for an address, with [shadPS4's checks](https://github.com/shadps4-emu/shadPS4/blob/a808e76/src/core/libraries/kernel/process.cpp#L243-L258) in their order: `EFAULT` for a null pointer, `EINVAL` when `st_size` is not 0x1A8, `ESRCH` for an unknown handle. `sceKernelGetModuleListInternal` returns the same list as `sceKernelGetModuleList`, as [fpPS4](https://github.com/red-prig/fpPS4/blob/04cefd4/kernel/ps4_libkernel.pas#L852-L858) does; fpPS4 marks that as a guess, and neither is checked on a PS5
|
||||
- [chroot](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) follows FreeBSD 11.4's [`sys_chroot`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/sys/kern/vfs_syscalls.c#L776-L807) and [`pwd_chroot`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/sys/kern/kern_descrip.c#L3059-L3085) for a root caller: `EFAULT` for a null path, `ENOENT` for an empty or missing one, `ENAMETOOLONG` for a path of 1024 bytes or more or a component over 255, and `ENOTDIR` for a path that is not a directory or passes through a file. A directory that is the guest root (`/`, `/..`, or `.` after `fchdir` to a descriptor of `/`) succeeds and changes nothing, as the root stays the same directory; the guest is taken never to have changed its root, so open directory descriptors do not make it fail with `EPERM` (`kern.chroot_allow_open_directories` 1). Any other directory throws, naming the path: the guest path resolver has a fixed root and mount aliases (`/app0`, `/savedata0`) that do not move with it. On the console a title starts in a sandbox root, where `pwd_chroot` refuses with `EPERM` while a directory is open; whether that holds for titles, and whether a title holds `PRIV_VFS_CHROOT`, are unverified. Porpoise (PPSA99764) weak-imports it and calls it only as `fchdir` to its saved descriptor of `/` then `chroot(".")`, to put its sandbox root back after a jailbreak daemon replaced it ([`put_root_back`](https://github.com/elripalda/Porpoise-Dolphin-Emulator-for-PS5/blob/2ed1ab5a06995aa198f7bccd4da0f90c3fc29d39/src/porpoise_jailbreak.cpp#L303-L331))
|
||||
- [Console identity](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) - `get_authinfo` errors and capability bits remain unverified on PS5; they follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/396c2a09a38d22eaa02aab32c1967263dceab95f/src/core/libraries/kernel/kernel.cpp), leaving the authority ID and other capability, attribute and credential words zero. The host models a retail unit (`IsCEX` 1, `IsDevKit` 0). The system OpenPSID reuses the ordinary ID; firmware 13.42 reads a separate `machdep.openpsid_for_sys`, whose value is unknown. Null returns positive 22 per the [module report](https://github.com/boykopovar/AnyPS5/pull/10524#issuecomment-6393566914).
|
||||
- [fchown](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) - ownership is not modelled: the guest's own owner and group (0) and the unchanged value (-1) are accepted, a descriptor that is not open fails with `EBADF`, and any other owner or group throws, naming it. The check reads the descriptor with `fstat`, ignoring the CRT's invalid-parameter handler on Windows as `DescriptorControl` does. The console's ownership rules are unverified. Morrowind (`mshivam019/morrowind-ps5`) imports it
|
||||
- [chown, lchown and fchownat](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) - ownership is not modelled, as for `fchown`: owner and group 0 and the unchanged value (-1) are accepted, and any other owner or group throws, naming it. The path is looked up first, as in FreeBSD 11's `kern_fchownat`, with `stat`, with `lstat` for `lchown`, and with `fstatat` for `fchownat`, so a lookup error is returned before the owner is checked and nothing is changed on the host. `fchownat` flags other than `AT_SYMLINK_NOFOLLOW` (0x200) return `EINVAL`, as in FreeBSD 11. The console's ownership rules are unverified
|
||||
- [linkat](../../../core/libs/prx/libkernel_sys/Export.cpp) (libkernel_sys) resolves `AT_FDCWD` (-100) and absolute paths as `link` does, and flags other than `AT_SYMLINK_FOLLOW` (0x400) return `EINVAL`, as in FreeBSD 11. Any other relative path is joined to the descriptor's host directory, found the same way as for `fchdir`, so guest path aliases and case-insensitive name matching do not apply to it, and a `..` component is not kept inside the guest root. It returns `EBADF` for a descriptor that is not open and `ENOTDIR` for one that is not a directory. A symbolic link as the source without `AT_SYMLINK_FOLLOW` throws, where FreeBSD links the symbolic link itself. Console behaviour is unverified
|
||||
|
||||
Reference in new issue
Block a user