fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
Titles check for a plugin with sceKernelStat before loading it through the engine path. The relinker emits only X.prx.guest.prx, so the check failed and PSNCore started with the raw (0, NULL) arguments. Share the dlopen mapping with sceKernelStat, read-only sceKernelOpen and sceKernelCheckReachability when the original name is absent.
This commit is contained in:
parent
a60f52e318
commit
f80a2f5535
|
|
@ -14,6 +14,7 @@ extern "C" void CxaFinalize_nid_no_patch(void* dsoHandle);
|
|||
extern "C" bool StopAtPrefixLetter_nid_no_patch(const char* str, char** endptr, int base);
|
||||
|
||||
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path);
|
||||
extern "C" std::filesystem::path RelinkedModulePath_nid_no_patch(const std::filesystem::path& path);
|
||||
extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved);
|
||||
extern "C" bool FinalPathComponentIsDot_nid_no_patch(const char* path);
|
||||
// Guest path aliases: a guest prefix such as "/savedata0" (a save-data mount point) resolves to a host
|
||||
|
|
|
|||
|
|
@ -345,6 +345,13 @@ extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path) {
|
|||
return Resolve(state, path);
|
||||
}
|
||||
|
||||
extern "C" std::filesystem::path RelinkedModulePath_nid_no_patch(const std::filesystem::path& path) {
|
||||
auto relinked = path;
|
||||
relinked += ".guest.prx";
|
||||
std::error_code error;
|
||||
return std::filesystem::is_regular_file(relinked, error) ? relinked : path;
|
||||
}
|
||||
|
||||
extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved) {
|
||||
if (resolved == nullptr) return 14;
|
||||
auto& state = Directories();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
namespace File {
|
||||
|
||||
std::filesystem::path PathOrRelinkedModule(const std::filesystem::path& nativePath);
|
||||
void FillFileStat(const std::filesystem::path& nativePath, FileStat* sb);
|
||||
void FillFileStat(int nativeDescriptor, FileStat* sb);
|
||||
bool FillFileStatFromDescriptor(int fd, FileStat* sb);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ static void CopyNativeStat(const NativeStat& st, FileStat* sb) {
|
|||
|
||||
namespace File {
|
||||
|
||||
std::filesystem::path PathOrRelinkedModule(const std::filesystem::path& nativePath) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(std::filesystem::symlink_status(nativePath, error))) return nativePath;
|
||||
return RelinkedModulePath_nid_no_patch(nativePath);
|
||||
}
|
||||
|
||||
void FillFileStat(const std::filesystem::path& nativePath, FileStat* sb) {
|
||||
NativeStat st{};
|
||||
if (DoStat(nativePath, &st) != 0) {
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode) {
|
|||
}
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
if ((flags & (SCE_KERNEL_O_ACCMODE | SCE_KERNEL_O_CREAT)) == SCE_KERNEL_O_RDONLY) native = File::PathOrRelinkedModule(native);
|
||||
return OpenNative(native, flags, mode);
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +288,7 @@ int APS5_VABI sceKernelStat(const char* path, FileStat* sb) {
|
|||
if (*path == '\0') return SceErrorFromErrno(2);
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
native = File::PathOrRelinkedModule(native);
|
||||
std::error_code error;
|
||||
constexpr int GuestEnotdir = 20;
|
||||
const auto status = std::filesystem::status(native, error);
|
||||
|
|
|
|||
|
|
@ -789,6 +789,7 @@ int APS5_VABI sceKernelCheckReachability(const char* path) {
|
|||
if (std::strlen(path) > 255) return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
native = File::PathOrRelinkedModule(native);
|
||||
std::error_code error;
|
||||
return std::filesystem::exists(native, error) ? 0 : SCE_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,13 +162,6 @@ static void InitializeDeferredModule(HMODULE native) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static std::filesystem::path RelinkedModulePath(const std::filesystem::path& path) {
|
||||
auto relinked = path;
|
||||
relinked += ".guest.prx";
|
||||
std::error_code error;
|
||||
return std::filesystem::is_regular_file(relinked, error) ? relinked : path;
|
||||
}
|
||||
|
||||
void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
||||
if ((flags & ~0x103) || (flags & 3) == 0 || (flags & 3) == 3) {
|
||||
Error("dlopen: unsupported flags"); return nullptr;
|
||||
|
|
@ -182,7 +175,7 @@ void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
|||
module->owned = false;
|
||||
} else {
|
||||
if (!*path) { Error("dlopen: empty module path"); return nullptr; }
|
||||
const auto resolved = RelinkedModulePath(ResolvePath_nid_no_patch(path));
|
||||
const auto resolved = RelinkedModulePath_nid_no_patch(ResolvePath_nid_no_patch(path));
|
||||
module->native = LoadLibraryExW(resolved.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (module->native) InitializeDeferredModule(static_cast<HMODULE>(module->native));
|
||||
}
|
||||
|
|
@ -192,7 +185,7 @@ void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
|||
Error(message); return nullptr;
|
||||
}
|
||||
#else
|
||||
const auto resolved = path ? RelinkedModulePath(ResolvePath_nid_no_patch(path)).string() : std::string{};
|
||||
const auto resolved = path ? RelinkedModulePath_nid_no_patch(ResolvePath_nid_no_patch(path)).string() : std::string{};
|
||||
const int nativeFlags = ((flags & 3) == 1 ? RTLD_LAZY : RTLD_NOW) |
|
||||
((flags & 0x100) ? RTLD_GLOBAL : RTLD_LOCAL);
|
||||
module->native = ::dlopen(path ? resolved.c_str() : nullptr, nativeFlags);
|
||||
|
|
|
|||
|
|
@ -174,8 +174,36 @@ static void TestParentTraversal() {
|
|||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
static void TestRelinkedModuleNames() {
|
||||
const auto root = std::filesystem::path("anyps5-relinked-names-" +
|
||||
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
||||
Require(std::filesystem::create_directories(root));
|
||||
const auto original = (root / "Plugin.prx").generic_string();
|
||||
const auto relinked = original + ".guest.prx";
|
||||
FileStat status{};
|
||||
Require(sceKernelStat(original.c_str(), &status) == static_cast<int>(0x80020002u));
|
||||
Require(sceKernelCheckReachability(original.c_str()) == static_cast<int>(0x80020002u));
|
||||
Require(sceKernelOpen(original.c_str(), 0, 0) == static_cast<int>(0x80020002u));
|
||||
{ std::ofstream file(relinked); file << "relinked"; }
|
||||
Require(sceKernelStat(original.c_str(), &status) == 0 && status.st_size == 8);
|
||||
Require(stat_nid_postfix(original.c_str(), &status) == 0 && status.st_size == 8);
|
||||
Require(sceKernelCheckReachability(original.c_str()) == 0);
|
||||
const int opened = sceKernelOpen(original.c_str(), 0, 0);
|
||||
Require(opened >= 0 && sceKernelClose(opened) == 0);
|
||||
Require(sceKernelStat((root / "Other.prx").generic_string().c_str(), &status) == static_cast<int>(0x80020002u));
|
||||
Require(!std::filesystem::exists(original));
|
||||
{ std::ofstream file(original); file << "original-bytes"; }
|
||||
Require(sceKernelStat(original.c_str(), &status) == 0 && status.st_size == 14);
|
||||
Require(std::filesystem::remove(original));
|
||||
const int created = sceKernelOpen(original.c_str(), 0x601, 0600);
|
||||
Require(created >= 0 && sceKernelClose(created) == 0);
|
||||
Require(std::filesystem::file_size(original) == 0 && std::filesystem::file_size(relinked) == 8);
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestParentTraversal();
|
||||
TestRelinkedModuleNames();
|
||||
Require(chmod_nid_postfix(nullptr, 0600) == -1 && *__error_nid_postfix() == 14);
|
||||
Require(sceKernelChmod_nid_postfix(nullptr, 0600) == static_cast<int>(0x8002000eu));
|
||||
Require(chmod_nid_postfix("", 0600) == -1 && *__error_nid_postfix() == 2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue