Files
AnyPS5/core/libs/tests/GuestProtectionReport.cpp
T
hugodearaujo 514b6849ec fix(libkernel): report the read bit of every write bit in a mapping's protection
A PS5 (firmware 13.60) reports CPU write 0x2 with CPU read 0x1, 0x80 with 0x40 and 0x200 with 0x100 after a map, sceKernelMprotect, sceKernelMtypeprotect or POSIX mprotect; GPU write 0x20 keeps GPU read 0x10 clear. sceKernelVirtualQuery and sceKernelQueryMemoryProtection now report the protection that way.
2026-10-19 12:05:39 +02:00

85 lines
3.9 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include "SceTypes.hpp"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <exception>
extern "C" {
int APS5_VABI mprotect_nid_postfix(void*, std::size_t, int) noexcept;
int APS5_VABI sceKernelMapFlexibleMemory(void**, std::size_t, int, int);
int APS5_VABI sceKernelAllocateDirectMemory(std::int64_t, std::int64_t, std::size_t, std::size_t, int, std::int64_t*);
int APS5_VABI sceKernelMapDirectMemory(void**, std::size_t, int, int, std::int64_t, std::size_t);
int APS5_VABI sceKernelMprotect(const void*, std::size_t, int);
int APS5_VABI sceKernelMunmap(std::uint64_t, std::size_t);
int APS5_VABI sceKernelVirtualQuery(const void*, int, VirtualQueryInfo*, std::uint64_t);
int APS5_VABI sceKernelQueryMemoryProtection(void*, void**, void**, int*);
}
namespace {
constexpr std::size_t Page = 0x4000;
void Require(bool condition, const char* what) {
if (condition) return;
std::fprintf(stderr, "%s\n", what);
std::abort();
}
void RequireReported(void* address, int expected, const char* what) {
VirtualQueryInfo info{};
Require(sceKernelVirtualQuery(address, 0, &info, sizeof(info)) == 0, "virtual query of a mapped page failed");
void* start = nullptr;
void* end = nullptr;
int protection = -1;
Require(sceKernelQueryMemoryProtection(address, &start, &end, &protection) == 0, "protection query of a mapped page failed");
if (info.protection == expected && protection == expected) return;
std::fprintf(stderr, "%s: reported 0x%x (virtual query) and 0x%x (protection query), expected 0x%x\n", what, info.protection, protection, expected);
std::abort();
}
void ProtectedReports() {
void* mapped = nullptr;
Require(sceKernelMapFlexibleMemory(&mapped, Page, 0x2, 0) == 0 && mapped != nullptr, "write-only flexible map failed");
RequireReported(mapped, 0x3, "a write-only flexible mapping");
struct Case {
int requested;
int reported;
};
constexpr Case Cases[] = {
{0x1, 0x1}, {0x2, 0x3}, {0x3, 0x3}, {0x10, 0x10}, {0x12, 0x13}, {0x20, 0x20}, {0x22, 0x23}, {0x30, 0x30}, {0x40, 0x40}, {0x80, 0xc0}, {0x82, 0xc3}, {0x100, 0x100}, {0x200, 0x300},
{0x202, 0x303}, {0x220, 0x320}, {0x2a2, 0x3e3}, {0xf2, 0xf3}, {0x3f2, 0x3f3}, {static_cast<int>(0xfffffff2u), 0x3f3},
};
for (const auto& item : Cases) {
Require(sceKernelMprotect(mapped, Page, item.requested) == 0, "sceKernelMprotect failed");
char what[64];
std::snprintf(what, sizeof(what), "sceKernelMprotect 0x%x", static_cast<unsigned>(item.requested));
RequireReported(mapped, item.reported, what);
}
Require(mprotect_nid_postfix(mapped, Page, 0x2) == 0, "write-only mprotect failed");
RequireReported(mapped, 0x3, "mprotect with PROT_WRITE");
Require(sceKernelMunmap(reinterpret_cast<std::uint64_t>(mapped), Page) == 0, "unmap of the flexible mapping failed");
std::int64_t physical = 0;
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, Page, 0, 0, &physical) == 0, "direct memory allocation failed");
void* direct = nullptr;
Require(sceKernelMapDirectMemory(&direct, Page, 0xf2, 0, physical, 0) == 0 && direct != nullptr, "direct map with 0xf2 failed");
RequireReported(direct, 0xf3, "a direct mapping with 0xf2");
Require(sceKernelMprotect(direct, Page, static_cast<int>(0xfffffff2u)) == 0, "sceKernelMprotect of the direct mapping failed");
RequireReported(direct, 0x3f3, "a direct mapping protected with 0xfffffff2");
Require(sceKernelMunmap(reinterpret_cast<std::uint64_t>(direct), Page) == 0, "unmap of the direct mapping failed");
}
}
int main() {
try {
ProtectedReports();
} catch (const std::exception& error) {
std::fprintf(stderr, "unexpected exception: %s\n", error.what());
return 1;
}
std::puts("reported protections include the read bit of every write bit");
return 0;
}