vm: Fix an overflow at vm::alloc, fix vm::find_map (#10760)

* The statement addr += align could have overflowed resulting in either infinite loop or allocating memory outside of the region (illegal).
Add a check checking if it's the last iteration of the loop, then break without adding.

* vm::find_map condition didn't consider the size of the map to be allocated, allowing illegal occupation of [<=0xB000'0000]-0xCFFF'FFFF. (0xC000'0000-0xCFFF'FFFF is reserved for RSX)
This commit is contained in:
Eladash 2021-08-26 18:14:08 +03:00 committed by GitHub
parent b0e352c44e
commit 2d9929059f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 28 additions and 2 deletions

View File

@ -1205,15 +1205,29 @@ namespace vm
shm = std::make_shared<utils::shm>(size);
}
const u32 max = (this->addr + this->size - size) & (0 - align);
u32 addr = utils::align(this->addr, align);
if (this->addr > std::min(max, addr))
{
return 0;
}
vm::writer_lock lock(0);
// Search for an appropriate place (unoptimized)
for (u32 addr = utils::align(this->addr, align); u64{addr} + size <= u64{this->addr} + this->size; addr += align)
for (;; addr += align)
{
if (try_alloc(addr, pflags, size, std::move(shm)))
{
return addr + (flags & stack_guarded ? 0x1000 : 0);
}
if (addr == max)
{
break;
}
}
return 0;
@ -1417,12 +1431,24 @@ namespace vm
static std::shared_ptr<block_t> _find_map(u32 size, u32 align, u64 flags)
{
for (u32 addr = utils::align<u32>(0x20000000, align); addr - 1 < 0xC0000000 - 1; addr += align)
const u32 max = (0xC0000000 - size) & (0 - align);
if (size > 0xC0000000 - 0x20000000 || max < 0x20000000)
{
return nullptr;
}
for (u32 addr = utils::align<u32>(0x20000000, align);; addr += align)
{
if (_test_map(addr, size))
{
return std::make_shared<block_t>(addr, size, flags);
}
if (addr == max)
{
break;
}
}
return nullptr;