mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
fix(libc): leave resident runs under an open host write out of MapAlias
demote() fences a resident run read-only, copies it into the section and replaces its pages with views. A host write between BeginHostWrite and EndHostWrite runs outside the mapping lock, so one in flight on the run could fail on the fence (an APR file read raised ios_base::failure) or land in the private pages after the copy and be lost. MapAlias now returns null without demoting when any page of a run it would demote has an open host write; the AGC driver then imports the range without an alias, as before this change. A blocking host write such as a socket receive must not stall the import, so MapAlias does not wait. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d8de2d187
commit
22091410a6
2 files changed
+31
No files matched your search
@@ -256,6 +256,14 @@ public:
|
||||
return std::runtime_error(text);
|
||||
};
|
||||
if (address % pageBytes != 0 || bytes % pageBytes != 0 || bytes == 0) throw refuse("the range is not made of whole shared pages");
|
||||
for (std::size_t done = 0; done < bytes; done += pageBytes) {
|
||||
const auto found = views.find(address + done);
|
||||
if (found == views.end() || !found->second.resident) continue;
|
||||
const auto run = std::prev(residentRuns.upper_bound(address + done));
|
||||
for (auto page = views.find(run->first); page != views.end() && page->first < run->second.end; ++page) {
|
||||
if (page->second.hostWrites != 0) return nullptr;
|
||||
}
|
||||
}
|
||||
for (std::size_t done = 0; done < bytes; done += pageBytes) {
|
||||
const auto found = views.find(address + done);
|
||||
if (found != views.end() && found->second.resident) demote(address + done);
|
||||
|
||||
@@ -1189,6 +1189,28 @@ static void CheckAliasAcrossDirectAllocations() {
|
||||
Require(sceKernelReleaseDirectMemory(first, page * 3) == 0);
|
||||
}
|
||||
|
||||
static void CheckAliasLeavesResidentRunsUnderAHostWrite() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
std::int64_t phys = 0;
|
||||
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, page * 2, 0, 0, &phys) == 0);
|
||||
void* mapped = nullptr;
|
||||
Require(sceKernelMapDirectMemory(&mapped, page * 2, 3, 0, phys, 0) == 0);
|
||||
auto* bytes = static_cast<volatile unsigned char*>(mapped);
|
||||
bytes[5] = 0x11;
|
||||
{
|
||||
const GuestArena::HostWrite open(static_cast<unsigned char*>(mapped) + page, page);
|
||||
Require(open.Open());
|
||||
Require(GuestArena::GuestArenaMapAlias_nid_postfix(reinterpret_cast<std::uintptr_t>(mapped), page * 2) == nullptr);
|
||||
bytes[page + 5] = 0x22;
|
||||
}
|
||||
auto* alias = static_cast<volatile unsigned char*>(GuestArena::GuestArenaMapAlias_nid_postfix(reinterpret_cast<std::uintptr_t>(mapped), page * 2));
|
||||
Require(alias != nullptr && alias[5] == 0x11 && alias[page + 5] == 0x22);
|
||||
GuestArena::GuestArenaUnmapAlias_nid_postfix(const_cast<unsigned char*>(alias));
|
||||
Require(bytes[5] == 0x11 && bytes[page + 5] == 0x22);
|
||||
Require(sceKernelMunmap(mapped, page * 2) == 0);
|
||||
Require(sceKernelReleaseDirectMemory(phys, page * 2) == 0);
|
||||
}
|
||||
|
||||
static void CheckAliasRefusesPagesThatAreNotSharedViews() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
std::int64_t phys = 0;
|
||||
@@ -2574,6 +2596,7 @@ int main(int argc, char** argv) {
|
||||
CheckAliasAcrossDirectAllocations();
|
||||
CheckAliasOfReorderedSharedPages();
|
||||
CheckAliasRefusesPagesThatAreNotSharedViews();
|
||||
CheckAliasLeavesResidentRunsUnderAHostWrite();
|
||||
#endif
|
||||
CheckUnhintedKernelMappingsLandInTheWindow();
|
||||
#if defined(__linux__)
|
||||
|
||||
Reference in new issue
Block a user