feat(libkernel): implement POSIX mprotect

mprotect changes the protection of guest memory through the same path
as sceKernelMprotect and reports failures through errno: EINVAL for a
null or overflowing range or a range the allocation tracker rejects,
ENOMEM when allocation fails. A zero length succeeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kjhq 2026-10-07 10:41:01 +00:00 committed by Adrià Franch
parent 7a178e2276
commit 35ae8742a9
2 changed files with 34 additions and 0 deletions

View File

@ -78,4 +78,23 @@ int APS5_VABI munmap_nid_postfix(void* address, std::size_t length) noexcept {
}
}
int APS5_VABI mprotect_nid_postfix(void* address, std::size_t length, int protection) noexcept {
const auto failed = [](int error) {
SetError(error);
return -1;
};
const auto start = reinterpret_cast<std::uintptr_t>(address);
if (length == 0) return 0;
if (start == 0 || length > std::numeric_limits<std::uintptr_t>::max() - start)
return failed(GuestInvalid);
try {
if (DoMprotect(address, length, protection) != 0) return failed(GuestInvalid);
return 0;
} catch (const std::bad_alloc&) {
return failed(GuestNoMemory);
} catch (const std::exception&) {
return failed(GuestInvalid);
}
}
}

View File

@ -36,6 +36,7 @@
extern "C" {
void* APS5_VABI mmap_nid_postfix(void*, std::size_t, int, int, int, std::int64_t) noexcept;
int APS5_VABI munmap_nid_postfix(void*, std::size_t) noexcept;
int APS5_VABI mprotect_nid_postfix(void*, std::size_t, int) noexcept;
int* APS5_VABI __error_nid_postfix();
int APS5_VABI sceKernelMapNamedFlexibleMemory(void**, std::size_t, int, int, const char*);
int APS5_VABI sceKernelMapNamedFlexibleMemoryInternal(void**, std::size_t, int, int, const char*);
@ -1099,6 +1100,20 @@ int main() {
const auto range = mutation.Find(memory);
Require(range.bytes == page * 3 && range.readable && range.writable);
}
Require(mprotect_nid_postfix(memory, 0, 1) == 0);
Require(mprotect_nid_postfix(nullptr, page, 1) == -1 && *__error_nid_postfix() == 22);
Require(mprotect_nid_postfix(memory + 1, 1, 1) == 0);
{
GuestAllocations::Mutation mutation;
const auto range = mutation.Find(memory);
Require(range.readable && !range.writable);
}
Require(memory[0] == 42);
Require(mprotect_nid_postfix(memory, page, 3) == 0);
{
GuestAllocations::Mutation mutation;
Require(mutation.Find(memory).writable);
}
Require(munmap_nid_postfix(memory + 1, page) == -1 && *__error_nid_postfix() == 22);
Require(munmap_nid_postfix(memory, 0) == -1 && *__error_nid_postfix() == 22);
Require(memory[0] == 42);