Kernel: Fix incorrect EFAULTs when syscall would write into COW pages.

This commit is contained in:
Andreas Kling 2019-01-25 01:39:15 +01:00
parent a4a106a430
commit 11b73c38d8
Notes: sideshowbarker 2024-07-19 15:57:30 +09:00
4 changed files with 38 additions and 32 deletions

View file

@ -208,7 +208,18 @@ Region* MemoryManager::region_from_laddr(Process& process, LinearAddress laddr)
if (region->contains(laddr))
return region.ptr();
}
kprintf("%s(%u) Couldn't find region for L%x (CR3=%x)\n", process.name().characters(), process.pid(), laddr.get(), process.page_directory().cr3());
dbgprintf("%s(%u) Couldn't find region for L%x (CR3=%x)\n", process.name().characters(), process.pid(), laddr.get(), process.page_directory().cr3());
return nullptr;
}
const Region* MemoryManager::region_from_laddr(const Process& process, LinearAddress laddr)
{
// FIXME: Use a binary search tree (maybe red/black?) or some other more appropriate data structure!
for (auto& region : process.m_regions) {
if (region->contains(laddr))
return region.ptr();
}
dbgprintf("%s(%u) Couldn't find region for L%x (CR3=%x)\n", process.name().characters(), process.pid(), laddr.get(), process.page_directory().cr3());
return nullptr;
}
@ -515,34 +526,14 @@ bool MemoryManager::map_region(Process& process, Region& region)
bool MemoryManager::validate_user_read(const Process& process, LinearAddress laddr) const
{
dword pageDirectoryIndex = (laddr.get() >> 22) & 0x3ff;
dword pageTableIndex = (laddr.get() >> 12) & 0x3ff;
auto pde = PageDirectoryEntry(&const_cast<Process&>(process).page_directory().entries()[pageDirectoryIndex]);
if (!pde.is_present())
return false;
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
if (!pte.is_present())
return false;
if (process.isRing3() && !pte.is_user_allowed())
return false;
return true;
auto* region = region_from_laddr(process, laddr);
return region && region->is_readable();
}
bool MemoryManager::validate_user_write(const Process& process, LinearAddress laddr) const
{
dword pageDirectoryIndex = (laddr.get() >> 22) & 0x3ff;
dword pageTableIndex = (laddr.get() >> 12) & 0x3ff;
auto pde = PageDirectoryEntry(&const_cast<Process&>(process).page_directory().entries()[pageDirectoryIndex]);
if (!pde.is_present())
return false;
auto pte = PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
if (!pte.is_present())
return false;
if (process.isRing3() && !pte.is_user_allowed())
return false;
if (!pte.is_writable())
return false;
return true;
auto* region = region_from_laddr(process, laddr);
return region && region->is_writable();
}
RetainPtr<Region> Region::clone()

View file

@ -246,6 +246,7 @@ private:
void remove_identity_mapping(PageDirectory&, LinearAddress, size_t);
static Region* region_from_laddr(Process&, LinearAddress);
static const Region* region_from_laddr(const Process&, LinearAddress);
bool copy_on_write(Region&, unsigned page_index_in_region);
bool page_in_from_inode(Region&, unsigned page_index_in_region);

View file

@ -1605,20 +1605,34 @@ bool Process::validate_read_from_kernel(LinearAddress laddr) const
bool Process::validate_read(const void* address, size_t size) const
{
if ((reinterpret_cast<dword>(address) & PAGE_MASK) != ((reinterpret_cast<dword>(address) + (size - 1)) & PAGE_MASK)) {
if (!MM.validate_user_read(*this, LinearAddress((dword)address).offset(size)))
if (isRing0())
return true;
ASSERT(size);
if (!size)
return false;
LinearAddress first_address((dword)address);
LinearAddress last_address = first_address.offset(size - 1);
if (first_address.page_base() != last_address.page_base()) {
if (!MM.validate_user_read(*this, last_address))
return false;
}
return MM.validate_user_read(*this, LinearAddress((dword)address));
return MM.validate_user_read(*this, first_address);
}
bool Process::validate_write(void* address, size_t size) const
{
if ((reinterpret_cast<dword>(address) & PAGE_MASK) != ((reinterpret_cast<dword>(address) + (size - 1)) & PAGE_MASK)) {
if (!MM.validate_user_write(*this, LinearAddress((dword)address).offset(size)))
if (isRing0())
return true;
ASSERT(size);
if (!size)
return false;
LinearAddress first_address((dword)address);
LinearAddress last_address = first_address.offset(size - 1);
if (first_address.page_base() != last_address.page_base()) {
if (!MM.validate_user_write(*this, last_address))
return false;
}
return MM.validate_user_write(*this, LinearAddress((dword)address));
return MM.validate_user_write(*this, last_address);
}
pid_t Process::sys$getsid(pid_t pid)

View file

@ -90,7 +90,7 @@ int main(int, char**)
}
if (FD_ISSET(ptm_fd, &rfds)) {
byte buffer[1024];
byte buffer[4096];
ssize_t nread = read(ptm_fd, buffer, sizeof(buffer));
if (nread < 0) {
dbgprintf("Terminal read error: %s\n", strerror(errno));