diff --git a/core/memory/memory.cpp b/core/memory/memory.cpp index 077d0f9..79e4121 100644 --- a/core/memory/memory.cpp +++ b/core/memory/memory.cpp @@ -122,13 +122,13 @@ NIF void MapFramebuffer(PageTable *PT) { vmm.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress, - fbSize, RW | G); + fbSize, RW | G | KRsv); } else { vmm.Map(bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress, - fbSize, RW | G); + fbSize, RW | G | KRsv); } itrfb++; } @@ -190,7 +190,7 @@ NIF void MapKernel(PageTable *PT) { for (k = BootstrapStart; k < BootstrapEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -204,7 +204,7 @@ NIF void MapKernel(PageTable *PT) /* Text section */ for (k = KernelTextStart; k < KernelTextEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -212,7 +212,7 @@ NIF void MapKernel(PageTable *PT) /* Data section */ for (k = KernelDataStart; k < KernelDataEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -220,7 +220,7 @@ NIF void MapKernel(PageTable *PT) /* Read only data section */ for (k = KernelRoDataStart; k < KernelRoDataEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)BaseKernelMapAddress, G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, G | KRsv); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -228,7 +228,7 @@ NIF void MapKernel(PageTable *PT) /* Block starting symbol section */ for (k = KernelBssStart; k < KernelBssEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G | KRsv); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -240,7 +240,7 @@ NIF void MapKernel(PageTable *PT) { for (k = KernelFileStart; k < KernelFileEnd; k += PAGE_SIZE) { - vmm.Map((void *)k, (void *)k, G); + vmm.Map((void *)k, (void *)k, G | KRsv); KernelAllocator.ReservePage((void *)k); } } diff --git a/core/memory/stack_guard.cpp b/core/memory/stack_guard.cpp index e25c1e7..6f9fdf6 100644 --- a/core/memory/stack_guard.cpp +++ b/core/memory/stack_guard.cpp @@ -38,7 +38,7 @@ namespace Memory debug("AllocatedStack: %#lx", AllocatedStack); memset(AllocatedStack, 0, USER_STACK_SIZE); - Virtual vmm = Virtual(this->vma->GetTable()); + Virtual vmm = Virtual(this->vma->Table); for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++) { void *VirtualPage = (void *)((uintptr_t)this->StackBottom - (i * PAGE_SIZE)); @@ -79,8 +79,8 @@ namespace Memory if (this->UserMode) { - std::vector ParentAllocatedPages = Parent->GetAllocatedPages(); - Virtual vma(this->vma->GetTable()); + std::list ParentAllocatedPages = Parent->GetAllocatedPages(); + Virtual vma(this->vma->Table); foreach (auto Page in ParentAllocatedPages) { void *NewPhysical = this->vma->RequestPages(1); @@ -114,7 +114,7 @@ namespace Memory debug("AllocatedStack: %#lx", AllocatedStack); { - Virtual vmm = Virtual(vma->GetTable()); + Virtual vmm = Virtual(vma->Table); for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++) { void *VirtualPage = (void *)(USER_STACK_BASE + (i * PAGE_SIZE)); diff --git a/core/memory/vma.cpp b/core/memory/vma.cpp index 328e213..6b2ba81 100644 --- a/core/memory/vma.cpp +++ b/core/memory/vma.cpp @@ -17,51 +17,14 @@ #include #include +#include #include +#include #include "../../kernel.h" namespace Memory { - // ReadFSFunction(MEM_Read) - // { - // if (Size <= 0) - // Size = node->Length; - - // if (RefOffset > node->Length) - // return 0; - - // if ((node->Length - RefOffset) == 0) - // return 0; /* EOF */ - - // if (RefOffset + (off_t)Size > node->Length) - // Size = node->Length; - - // memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size); - // return Size; - // } - - // WriteFSFunction(MEM_Write) - // { - // if (Size <= 0) - // Size = node->Length; - - // if (RefOffset > node->Length) - // return 0; - - // if (RefOffset + (off_t)Size > node->Length) - // Size = node->Length; - - // memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size); - // return Size; - // } - - // vfs::FileSystemOperations mem_op = { - // .Name = "mem", - // .Read = MEM_Read, - // .Write = MEM_Write, - // }; - uint64_t VirtualMemoryArea::GetAllocatedMemorySize() { SmartLock(MgrLock); @@ -71,120 +34,89 @@ namespace Memory return FROM_PAGES(Size); } - bool VirtualMemoryArea::Add(void *Address, size_t Count) + void *VirtualMemoryArea::RequestPages(size_t Count, bool User, bool Protect) { - SmartLock(MgrLock); - function("%#lx, %lld", Address, Count); - - if (Address == nullptr) - { - error("Address is null!"); - return false; - } - - if (Count == 0) - { - error("Count is 0!"); - return false; - } - - for (size_t i = 0; i < AllocatedPagesList.size(); i++) - { - if (AllocatedPagesList[i].Address == Address) - { - error("Address already exists!"); - return false; - } - else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address) - { - if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address) - { - error("Address intersects with an allocated page!"); - return false; - } - } - else - { - if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address) - { - error("Address intersects with an allocated page!"); - return false; - } - } - } - - AllocatedPagesList.push_back({Address, Count}); - return true; - } - - void *VirtualMemoryArea::RequestPages(size_t Count, bool User) - { - SmartLock(MgrLock); - function("%lld, %s", Count, User ? "true" : "false"); + function("%lld, %s, %s", Count, + User ? "true" : "false", + Protect ? "true" : "false"); void *Address = KernelAllocator.RequestPages(Count); memset(Address, 0, Count * PAGE_SIZE); - for (size_t i = 0; i < Count; i++) - { - int Flags = Memory::PTFlag::RW; - if (User) - Flags |= Memory::PTFlag::US; - void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); + int Flags = PTFlag::RW; + if (User) + Flags |= PTFlag::US; + if (Protect) + Flags |= PTFlag::KRsv; - Memory::Virtual vmm(this->Table); - vmm.Map(AddressToMap, AddressToMap, Flags); - } + Virtual vmm(this->Table); - AllocatedPagesList.push_back({Address, Count}); + SmartLock(MgrLock); + + vmm.Map(Address, Address, FROM_PAGES(Count), Flags); + AllocatedPagesList.push_back({Address, Count, Protect}); + debug("%#lx +{%#lx, %lld}", this, Address, Count); return Address; } void VirtualMemoryArea::FreePages(void *Address, size_t Count) { - SmartLock(MgrLock); function("%#lx, %lld", Address, Count); + SmartLock(MgrLock); forItr(itr, AllocatedPagesList) { - if (itr->Address == Address) + if (itr->Address != Address) + continue; + + if (itr->Protected) { - /** TODO: Advanced checks. Allow if the page count is less than the requested one. - * This will allow the user to free only a part of the allocated pages. - * - * But this will be in a separate function because we need to specify if we - * want to free from the start or from the end and return the new address. - */ - if (itr->PageCount != Count) - { - error("Page count mismatch! (Allocated: %lld, Requested: %lld)", itr->PageCount, Count); - return; - } - - KernelAllocator.FreePages(Address, Count); - - Memory::Virtual vmm(this->Table); - for (size_t i = 0; i < Count; i++) - { - void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); - vmm.Remap(AddressToMap, AddressToMap, Memory::PTFlag::RW); - // vmm.Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE))); - } - AllocatedPagesList.erase(itr); + error("Address %#lx is protected", Address); return; } + + /** TODO: Advanced checks. Allow if the page count is less than the requested one. + * This will allow the user to free only a part of the allocated pages. + * + * But this will be in a separate function because we need to specify if we + * want to free from the start or from the end and return the new address. + */ + if (itr->PageCount != Count) + { + error("Page count mismatch! (Allocated: %lld, Requested: %lld)", + itr->PageCount, Count); + return; + } + + Virtual vmm(this->Table); + for (size_t i = 0; i < Count; i++) + { + void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); + vmm.Remap(AddressToMap, AddressToMap, PTFlag::RW); + } + + KernelAllocator.FreePages(Address, Count); + AllocatedPagesList.erase(itr); + debug("%#lx -{%#lx, %lld}", this, Address, Count); + return; } } void VirtualMemoryArea::DetachAddress(void *Address) { - SmartLock(MgrLock); function("%#lx", Address); + SmartLock(MgrLock); forItr(itr, AllocatedPagesList) { if (itr->Address == Address) { + if (itr->Protected) + { + error("Address %#lx is protected", Address); + return; + } + AllocatedPagesList.erase(itr); return; } @@ -203,14 +135,14 @@ namespace Memory Fixed ? "true" : "false", Shared ? "true" : "false"); - Memory::Virtual vmm(this->Table); + Virtual vmm(this->Table); // FIXME // for (uintptr_t j = uintptr_t(Address); // j < uintptr_t(Address) + Length; // j += PAGE_SIZE) // { - // if (vmm.Check((void *)j, Memory::G)) + // if (vmm.Check((void *)j, G)) // { // if (Fixed) // return (void *)-EINVAL; @@ -230,6 +162,12 @@ namespace Memory } SmartLock(MgrLock); + if (vmm.Check(Address, PTFlag::KRsv)) + { + error("Cannot create CoW region at %#lx", Address); + return (void *)-EPERM; + } + vmm.Unmap(Address, Length); vmm.Map(Address, nullptr, Length, PTFlag::CoW); debug("CoW region created at range %#lx-%#lx for pt %#lx", @@ -254,8 +192,10 @@ namespace Memory bool VirtualMemoryArea::HandleCoW(uintptr_t PFA) { function("%#lx", PFA); - Memory::Virtual vmm(this->Table); - Memory::PageTableEntry *pte = vmm.GetPTE((void *)PFA); + Virtual vmm(this->Table); + PageTableEntry *pte = vmm.GetPTE((void *)PFA); + + debug("ctx: %#lx", this); if (!pte) { @@ -264,51 +204,51 @@ namespace Memory return false; } - if (pte->CopyOnWrite == true) + if (!pte->CopyOnWrite) { - foreach (auto sr in SharedRegions) + debug("PFA %#lx is not CoW (pt %#lx) (flags %#lx)", + PFA, this->Table, pte->raw); + return false; + } + + foreach (auto sr in SharedRegions) + { + uintptr_t Start = (uintptr_t)sr.Address; + uintptr_t End = (uintptr_t)sr.Address + sr.Length; + debug("Start: %#lx, End: %#lx (PFA: %#lx)", + Start, End, PFA); + + if (PFA >= Start && PFA < End) { - uintptr_t Start = (uintptr_t)sr.Address; - uintptr_t End = (uintptr_t)sr.Address + sr.Length; - - if (PFA >= Start && PFA < End) + if (sr.Shared) { - debug("Start: %#lx, End: %#lx (PFA: %#lx)", - Start, End, PFA); - - if (sr.Shared) - { - fixme("Shared CoW"); - return false; - } - else - { - void *pAddr = this->RequestPages(1); - if (pAddr == nullptr) - return false; - memset(pAddr, 0, PAGE_SIZE); - - assert(pte->Present == true); - pte->ReadWrite = sr.Write; - pte->UserSupervisor = sr.Read; - pte->ExecuteDisable = sr.Exec; - - pte->CopyOnWrite = false; - debug("PFA %#lx is CoW (pt %#lx, flags %#lx)", - PFA, this->Table, pte->raw); -#if defined(a64) - CPU::x64::invlpg((void *)PFA); -#elif defined(a32) - CPU::x32::invlpg((void *)PFA); -#endif - return true; - } + fixme("Shared CoW"); + return false; } + + void *pAddr = this->RequestPages(1); + if (pAddr == nullptr) + return false; + memset(pAddr, 0, PAGE_SIZE); + + assert(pte->Present == true); + pte->ReadWrite = sr.Write; + pte->UserSupervisor = sr.Read; + pte->ExecuteDisable = sr.Exec; + + pte->CopyOnWrite = false; + debug("PFA %#lx is CoW (pt %#lx, flags %#lx)", + PFA, this->Table, pte->raw); +#if defined(a64) + CPU::x64::invlpg((void *)PFA); +#elif defined(a32) + CPU::x32::invlpg((void *)PFA); +#endif + return true; } } - debug("PFA %#lx is not CoW (pt %#lx)", - PFA, this->Table); + debug("%#lx not found in CoW regions", PFA); return false; } @@ -318,11 +258,11 @@ namespace Memory foreach (auto ap in AllocatedPagesList) { KernelAllocator.FreePages(ap.Address, ap.PageCount); - Memory::Virtual vmm(this->Table); + Virtual vmm(this->Table); for (size_t i = 0; i < ap.PageCount; i++) vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), - Memory::PTFlag::RW); + PTFlag::RW); } AllocatedPagesList.clear(); } @@ -330,59 +270,66 @@ namespace Memory void VirtualMemoryArea::Fork(VirtualMemoryArea *Parent) { function("%#lx", Parent); + assert(Parent); - if (Parent == nullptr) - { - error("Parent is null!"); - return; - } + debug("parent apl:%d sr:%d [P:%#lx C:%#lx]", + Parent->AllocatedPagesList.size(), Parent->SharedRegions.size(), + Parent->Table, this->Table); + debug("ctx: this: %#lx parent: %#lx", this, Parent); - if (Parent->Table == nullptr) - { - error("Parent's table is null!"); - return; - } - - Memory::Virtual vmm(this->Table); + Virtual vmm(this->Table); SmartLock(MgrLock); - foreach (auto &ap in Parent->GetAllocatedPagesList()) + foreach (auto &ap in Parent->AllocatedPagesList) { + if (ap.Protected) + { + debug("Protected %#lx-%#lx", ap.Address, + (uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE)); + continue; /* We don't want to modify these pages. */ + } + MgrLock.Unlock(); void *Address = this->RequestPages(ap.PageCount); MgrLock.Lock(__FUNCTION__); if (Address == nullptr) return; - memcpy(Address, ap.Address, ap.PageCount * PAGE_SIZE); + memcpy(Address, ap.Address, FROM_PAGES(ap.PageCount)); - // map these new allocated pages to be the same as the parent for (size_t i = 0; i < ap.PageCount; i++) { void *AddressToMap = (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)); void *RealAddress = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); #if defined(a86) - Memory::PageTableEntry *pte = vmm.GetPTE(AddressToMap); + PageTableEntry *pte = vmm.GetPTE(AddressToMap); uintptr_t Flags = 0; - Flags |= pte->Present ? 1UL : 0; - Flags |= pte->ReadWrite ? 2UL : 0; - Flags |= pte->UserSupervisor ? 4UL : 0; - Flags |= pte->CopyOnWrite ? 512UL : 0; + Flags |= pte->Present ? (uintptr_t)PTFlag::P : 0; + Flags |= pte->ReadWrite ? (uintptr_t)PTFlag::RW : 0; + Flags |= pte->UserSupervisor ? (uintptr_t)PTFlag::US : 0; + Flags |= pte->CopyOnWrite ? (uintptr_t)PTFlag::CoW : 0; + Flags |= pte->KernelReserve ? (uintptr_t)PTFlag::KRsv : 0; - debug("Mapping %#lx to %#lx (flags %s/%s/%s/%s)", + debug("Mapping %#lx to %#lx (flags %s/%s/%s/%s/%s)", RealAddress, AddressToMap, Flags & PTFlag::P ? "P" : "-", Flags & PTFlag::RW ? "RW" : "-", Flags & PTFlag::US ? "US" : "-", - Flags & PTFlag::CoW ? "CoW" : "-"); - vmm.Map(AddressToMap, RealAddress, Flags); + Flags & PTFlag::CoW ? "CoW" : "-", + Flags & PTFlag::KRsv ? "KRsv" : "-"); + MgrLock.Unlock(); + this->Map(AddressToMap, RealAddress, PAGE_SIZE, Flags); + MgrLock.Lock(__FUNCTION__); #else -#warning "Not implemented" +#error "Not implemented" #endif } + + debug("Forked %#lx-%#lx", ap.Address, + (uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE)); } - foreach (auto &sr in Parent->GetSharedRegions()) + foreach (auto &sr in Parent->SharedRegions) { MgrLock.Unlock(); void *Address = this->CreateCoWRegion(sr.Address, sr.Length, @@ -392,53 +339,154 @@ namespace Memory if (Address == nullptr) return; memcpy(Address, sr.Address, sr.Length); + debug("Forked CoW region %#lx-%#lx", sr.Address, + (uintptr_t)sr.Address + sr.Length); } } - VirtualMemoryArea::VirtualMemoryArea(PageTable *Table) + int VirtualMemoryArea::Map(void *VirtualAddress, void *PhysicalAddress, + size_t Length, uint64_t Flags) { - debug("+ %#lx %s", this, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : ""); - + Virtual vmm(this->Table); SmartLock(MgrLock); - if (Table) - this->Table = Table; - else + + uintptr_t intVirtualAddress = (uintptr_t)VirtualAddress; + uintptr_t intPhysicalAddress = (uintptr_t)PhysicalAddress; + + for (uintptr_t va = intVirtualAddress; + va < intVirtualAddress + Length; va += PAGE_SIZE) + { + if (vmm.Check(VirtualAddress, PTFlag::KRsv)) + { + error("Virtual address %#lx is reserved", VirtualAddress); + return -EPERM; + } + } + + for (uintptr_t va = intPhysicalAddress; + va < intPhysicalAddress + Length; va += PAGE_SIZE) + { + if (vmm.Check(PhysicalAddress, PTFlag::KRsv)) + { + error("Physical address %#lx is reserved", PhysicalAddress); + return -EPERM; + } + } + + vmm.Map(VirtualAddress, PhysicalAddress, Length, Flags); + debug("Mapped %#lx-%#lx to %#lx-%#lx (flags %#lx)", + VirtualAddress, intVirtualAddress + Length, + PhysicalAddress, intPhysicalAddress + Length, + Flags); + return 0; + } + + int VirtualMemoryArea::Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags) + { + Virtual vmm(this->Table); + SmartLock(MgrLock); + + if (vmm.Check(VirtualAddress, PTFlag::KRsv)) + { + error("Virtual address %#lx is reserved", VirtualAddress); + return -EPERM; + } + + if (vmm.Check(PhysicalAddress, PTFlag::KRsv)) + { + error("Physical address %#lx is reserved", PhysicalAddress); + return -EPERM; + } + + vmm.Remap(VirtualAddress, PhysicalAddress, Flags); + debug("Remapped %#lx to %#lx (flags %#lx)", + VirtualAddress, PhysicalAddress, Flags); + return 0; + } + + int VirtualMemoryArea::Unmap(void *VirtualAddress, size_t Length) + { + Virtual vmm(this->Table); + SmartLock(MgrLock); + + uintptr_t intVirtualAddress = (uintptr_t)VirtualAddress; + + for (uintptr_t va = intVirtualAddress; + va < intVirtualAddress + Length; va += PAGE_SIZE) + { + if (vmm.Check(VirtualAddress, PTFlag::KRsv)) + { + error("Virtual address %#lx is reserved", VirtualAddress); + return -EPERM; + } + } + + vmm.Unmap(VirtualAddress, Length); + debug("Unmapped %#lx-%#lx", VirtualAddress, intVirtualAddress + Length); + return 0; + } + + void *VirtualMemoryArea::__UserCheckAndGetAddress(void *Address, size_t Length) + { + Virtual vmm(this->Table); + SmartLock(MgrLock); + + void *pAddress = this->Table->Get(Address); + if (pAddress == nullptr) + { + debug("Virtual address %#lx returns nullptr", Address); + return nullptr; + } + + uintptr_t intAddress = (uintptr_t)Address; + intAddress = ALIGN_DOWN(intAddress, PAGE_SIZE); + for (uintptr_t va = intAddress; va < intAddress + Length; va += PAGE_SIZE) + { + if (vmm.Check((void *)va, PTFlag::US)) + continue; + + fixme("Unable to get address %#lx, page is not user accessible", va); + return nullptr; + } + + return pAddress; + } + + int VirtualMemoryArea::__UserCheck(void *Address, size_t Length) + { + Virtual vmm(this->Table); + SmartLock(MgrLock); + + if (vmm.Check(Address, PTFlag::US)) + return 0; + + error("Address %#lx is not user accessible", Address); + return -EFAULT; + } + + VirtualMemoryArea::VirtualMemoryArea(PageTable *_Table) + : Table(_Table) + { + SmartLock(MgrLock); + if (_Table == nullptr) { if (TaskManager) + { + Tasking::PCB *pcb = thisProcess; + assert(pcb); this->Table = thisProcess->PageTable; + } else -#if defined(a64) - this->Table = (PageTable *)CPU::x64::readcr3().raw; -#elif defined(a32) - this->Table = (PageTable *)CPU::x32::readcr3().raw; -#endif + this->Table = (PageTable *)CPU::PageTable(); } } VirtualMemoryArea::~VirtualMemoryArea() { - debug("- %#lx %s", this, - KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : ""); - -#ifdef DEBUG - if (this->Table == KernelPageTable) - debug("Not remapping kernel page table allocated pages."); -#endif + /* No need to remap pages, the page table will be destroyed */ SmartLock(MgrLock); - Memory::Virtual vmm(this->Table); foreach (auto ap in AllocatedPagesList) - { KernelAllocator.FreePages(ap.Address, ap.PageCount); - - if (this->Table == KernelPageTable) - continue; - - for (size_t i = 0; i < ap.PageCount; i++) - vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), - (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), - Memory::PTFlag::RW); - } } } diff --git a/core/panic/ui.cpp b/core/panic/ui.cpp index 38e8884..f6ad691 100644 --- a/core/panic/ui.cpp +++ b/core/panic/ui.cpp @@ -424,13 +424,14 @@ nsa void DisplayDetailsScreen(CPU::ExceptionFrame *Frame) { Memory::Virtual vmm((Memory::PageTable *)Frame->cr3); if (vmm.GetMapType((void *)Frame->cr2) != Memory::Virtual::FourKiB) - ExPrint("Can't display page at address %#lx\n", Frame->cr2); + ExPrint("Can't display page %#lx\n", Frame->cr2); else { Memory::PageTableEntry *pte = vmm.GetPTE((void *)Frame->cr2); - ExPrint("Page %#lx: P:%d W:%d U:%d G:%d CoW:%d NX:%d\n", + ExPrint("Page %#lx: P:%d W:%d U:%d G:%d CoW:%d KRsv:%d NX:%d\n", ALIGN_DOWN(Frame->cr2, 0x1000), pte->Present, pte->ReadWrite, - pte->UserSupervisor, pte->Global, pte->CopyOnWrite, pte->ExecuteDisable); + pte->UserSupervisor, pte->Global, pte->CopyOnWrite, + pte->KernelReserve, pte->ExecuteDisable); } } diff --git a/include/memory/stack.hpp b/include/memory/stack.hpp index 2b295d2..f4992b7 100644 --- a/include/memory/stack.hpp +++ b/include/memory/stack.hpp @@ -19,7 +19,7 @@ #define __FENNIX_KERNEL_MEMORY_STACK_GUARD_H__ #include -#include +#include #include @@ -42,10 +42,10 @@ namespace Memory bool UserMode = false; bool Expanded = false; VirtualMemoryArea *vma = nullptr; - std::vector AllocatedPagesList; + std::list AllocatedPagesList; public: - std::vector GetAllocatedPages() + std::list GetAllocatedPages() { return AllocatedPagesList; } diff --git a/include/memory/table.hpp b/include/memory/table.hpp index 6859c23..925838e 100644 --- a/include/memory/table.hpp +++ b/include/memory/table.hpp @@ -59,7 +59,7 @@ namespace Memory CoW = 1 << 9, /** @brief Available 1 */ - AVL1 = 1 << 10, + KRsv = 1 << 10, /** @brief Available 2 */ AVL2 = 1 << 11, @@ -119,7 +119,7 @@ namespace Memory uintptr_t PageAttributeTable : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 - uintptr_t Available1 : 1; // 10 + uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t Address : 40; // 12-51 uintptr_t Available3 : 1; // 52 @@ -142,7 +142,7 @@ namespace Memory uintptr_t PageAttributeTable : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 - uintptr_t Available1 : 1; // 10 + uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t Address : 20; // 12-31 #elif defined(aa64) @@ -204,9 +204,22 @@ namespace Memory uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 - uintptr_t Available1 : 4; // 8-11 + uintptr_t KernelReserve : 1; // 8 + uintptr_t Available2 : 1; // 9 + uintptr_t Available3 : 1; // 10 + uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 - uintptr_t Available2 : 11; // 52-62 + uintptr_t Available5 : 1; // 52 + uintptr_t Available6 : 1; // 53 + uintptr_t Available7 : 1; // 54 + uintptr_t Available8 : 1; // 55 + uintptr_t Available9 : 1; // 56 + uintptr_t Available10 : 1; // 57 + uintptr_t Available11 : 1; // 58 + uintptr_t Available12 : 1; // 59 + uintptr_t Available13 : 1; // 60 + uintptr_t Available14 : 1; // 61 + uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; @@ -222,7 +235,7 @@ namespace Memory uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 - uintptr_t Available1 : 1; // 10 + uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Reserved0 : 8; // 13-20 @@ -248,7 +261,10 @@ namespace Memory uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 - uintptr_t Available1 : 4; // 8-11 + uintptr_t KernelReserve : 1; // 8 + uintptr_t Available2 : 1; // 9 + uintptr_t Available3 : 1; // 10 + uintptr_t Available4 : 1; // 11 uintptr_t Address : 20; // 12-31 }; @@ -264,7 +280,7 @@ namespace Memory uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 - uintptr_t Available1 : 1; // 10 + uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Address0 : 8; // 13-20 @@ -324,9 +340,22 @@ namespace Memory uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t PageSize : 1; // 7 - uintptr_t Available1 : 4; // 8-11 + uintptr_t KernelReserve : 1; // 8 + uintptr_t Available2 : 1; // 9 + uintptr_t Available3 : 1; // 10 + uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 - uintptr_t Available2 : 11; // 52-62 + uintptr_t Available5 : 1; // 52 + uintptr_t Available6 : 1; // 53 + uintptr_t Available7 : 1; // 54 + uintptr_t Available8 : 1; // 55 + uintptr_t Available9 : 1; // 56 + uintptr_t Available10 : 1; // 57 + uintptr_t Available11 : 1; // 58 + uintptr_t Available12 : 1; // 59 + uintptr_t Available13 : 1; // 60 + uintptr_t Available14 : 1; // 61 + uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; @@ -342,7 +371,7 @@ namespace Memory uintptr_t PageSize : 1; // 7 uintptr_t Global : 1; // 8 uintptr_t CopyOnWrite : 1; // 9 - uintptr_t Available1 : 1; // 10 + uintptr_t KernelReserve : 1; // 10 uintptr_t Available2 : 1; // 11 uintptr_t PageAttributeTable : 1; // 12 uintptr_t Reserved0 : 17; // 13-29 @@ -406,9 +435,22 @@ namespace Memory uintptr_t Accessed : 1; // 5 uintptr_t CopyOnWrite : 1; // 6 uintptr_t Reserved0 : 1; // 7 - uintptr_t Available1 : 4; // 8-11 + uintptr_t KernelReserve : 1; // 8 + uintptr_t Available2 : 1; // 9 + uintptr_t Available3 : 1; // 10 + uintptr_t Available4 : 1; // 11 uintptr_t Address : 40; // 12-51 - uintptr_t Available2 : 11; // 52-62 + uintptr_t Available5 : 1; // 52 + uintptr_t Available6 : 1; // 53 + uintptr_t Available7 : 1; // 54 + uintptr_t Available8 : 1; // 55 + uintptr_t Available9 : 1; // 56 + uintptr_t Available10 : 1; // 57 + uintptr_t Available11 : 1; // 58 + uintptr_t Available12 : 1; // 59 + uintptr_t Available13 : 1; // 60 + uintptr_t Available14 : 1; // 61 + uintptr_t Available15 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; #elif defined(aa64) @@ -460,9 +502,22 @@ namespace Memory uintptr_t Accessed : 1; // 5 uintptr_t Available0 : 1; // 6 uintptr_t Reserved0 : 1; // 7 - uintptr_t Available1 : 4; // 8-11 + uintptr_t KernelReserve : 1; // 8 + uintptr_t Available1 : 1; // 9 + uintptr_t Available2 : 1; // 10 + uintptr_t Available3 : 1; // 11 uintptr_t Address : 40; // 12-51 - uintptr_t Available2 : 11; // 52-62 + uintptr_t Available4 : 1; // 52 + uintptr_t Available5 : 1; // 53 + uintptr_t Available6 : 1; // 54 + uintptr_t Available7 : 1; // 55 + uintptr_t Available8 : 1; // 56 + uintptr_t Available9 : 1; // 57 + uintptr_t Available10 : 1; // 58 + uintptr_t Available11 : 1; // 59 + uintptr_t Available12 : 1; // 60 + uintptr_t Available13 : 1; // 61 + uintptr_t Available14 : 1; // 62 uintptr_t ExecuteDisable : 1; // 63 }; #elif defined(aa64) diff --git a/include/memory/vma.hpp b/include/memory/vma.hpp index 48fd473..1dfe835 100644 --- a/include/memory/vma.hpp +++ b/include/memory/vma.hpp @@ -22,12 +22,13 @@ #include #include #include -#include +#include #include namespace Memory { + class VirtualMemoryArea { public: @@ -35,6 +36,7 @@ namespace Memory { void *Address; size_t PageCount; + bool Protected; }; struct SharedRegion @@ -49,30 +51,15 @@ namespace Memory private: NewLock(MgrLock); Bitmap PageBitmap; - PageTable *Table; - std::vector AllocatedPagesList; - std::vector SharedRegions; + std::list AllocatedPagesList; + std::list SharedRegions; public: - PageTable *GetTable() { return Table; } - void SetTable(PageTable *Table) { this->Table = Table; } - - std::vector &GetAllocatedPagesList() - { - return AllocatedPagesList; - } - - std::vector &GetSharedRegions() - { - return SharedRegions; - } - + PageTable *Table = nullptr; uint64_t GetAllocatedMemorySize(); - bool Add(void *Address, size_t Count); - - void *RequestPages(size_t Count, bool User = false); + void *RequestPages(size_t Count, bool User = false, bool Protect = false); void FreePages(void *Address, size_t Count); void DetachAddress(void *Address); @@ -88,18 +75,45 @@ namespace Memory * @param Shared Shared region * @return Address of the region */ - void *CreateCoWRegion(void *Address, - size_t Length, + void *CreateCoWRegion(void *Address, size_t Length, bool Read, bool Write, bool Exec, bool Fixed, bool Shared); bool HandleCoW(uintptr_t PFA); - void FreeAllPages(); - void Fork(VirtualMemoryArea *Parent); - VirtualMemoryArea(PageTable *Table = nullptr); + void Reserve(void *Address, size_t Length); + void Unreserve(void *Address, size_t Length); + + int Map(void *VirtualAddress, void *PhysicalAddress, + size_t Length, uint64_t Flags); + int Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags); + int Unmap(void *VirtualAddress, size_t Length); + void *__UserCheckAndGetAddress(void *Address, size_t Length); + int __UserCheck(void *Address, size_t Length); + + template + T UserCheckAndGetAddress(T Address, size_t Length = 0) + { + if (Length == 0) + Length = sizeof(T); + + void *PhysAddr = __UserCheckAndGetAddress((void *)Address, Length); + if (PhysAddr == nullptr) + return {}; + return T(PhysAddr); + } + + template + int UserCheck(T Address, size_t Length = 0) + { + if (Length == 0) + Length = sizeof(T); + return __UserCheck((void *)Address, Length); + } + + VirtualMemoryArea(PageTable *Table); ~VirtualMemoryArea(); }; } diff --git a/syscalls/linux.cpp b/syscalls/linux.cpp index 2a7044f..8c728be 100644 --- a/syscalls/linux.cpp +++ b/syscalls/linux.cpp @@ -65,9 +65,14 @@ void linux_fork_return(void *tableAddr) static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) { PCB *pcb = thisProcess; - void *pBuf = pcb->PageTable->Get(buf); + Memory::VirtualMemoryArea *vma = pcb->vma; + + void *pBuf = vma->UserCheckAndGetAddress(buf, count); + if (pBuf == nullptr) + return -EFAULT; function("%d, %p, %d", fd, buf, count); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; ssize_t ret = fdt->_read(fd, pBuf, count); if (ret >= 0) @@ -79,9 +84,14 @@ static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) { PCB *pcb = thisProcess; - const void *pBuf = pcb->PageTable->Get((void *)buf); + Memory::VirtualMemoryArea *vma = pcb->vma; + + const void *pBuf = vma->UserCheckAndGetAddress(buf, count); + if (pBuf == nullptr) + return -EFAULT; function("%d, %p, %d", fd, buf, count); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; ssize_t ret = fdt->_write(fd, pBuf, count); if (ret) @@ -93,7 +103,11 @@ static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) { PCB *pcb = thisProcess; - const char *pPathname = pcb->PageTable->Get(pathname); + Memory::VirtualMemoryArea *vma = pcb->vma; + + const char *pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE); + if (pPathname == nullptr) + return -EFAULT; function("%s, %d, %d", pPathname, flags, mode); @@ -130,14 +144,11 @@ static int linux_stat(SysFrm *, const char *pathname, struct stat *statbuf) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)pathname, Memory::US)) - { - debug("Invalid address %#lx", pathname); + auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE); + if (pPathname == nullptr) return -EFAULT; - } - auto pPathname = pcb->PageTable->Get(pathname); return fdt->_stat(pPathname, statbuf); } @@ -148,14 +159,11 @@ static int linux_fstat(SysFrm *, int fd, struct stat *statbuf) #undef fstat PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)statbuf, Memory::US)) - { - debug("Invalid address %#lx", statbuf); + auto pStatbuf = vma->UserCheckAndGetAddress(statbuf); + if (pStatbuf == nullptr) return -EFAULT; - } - auto pStatbuf = pcb->PageTable->Get(statbuf); return fdt->_fstat(fd, pStatbuf); } @@ -166,22 +174,12 @@ static int linux_lstat(SysFrm *, const char *pathname, struct stat *statbuf) #undef lstat PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)pathname, Memory::US)) - { - debug("Invalid address %#lx", pathname); + auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE); + auto pStatbuf = vma->UserCheckAndGetAddress(statbuf); + if (pPathname == nullptr || pStatbuf == nullptr) return -EFAULT; - } - - if (!vmm.Check((void *)statbuf, Memory::US)) - { - debug("Invalid address %#lx", statbuf); - return -EFAULT; - } - - auto pPathname = pcb->PageTable->Get(pathname); - auto pStatbuf = pcb->PageTable->Get(statbuf); return fdt->_lstat(pPathname, pStatbuf); } @@ -291,7 +289,6 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, if (p_Read) { - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); void *pBuf = vma->RequestPages(TO_PAGES(length)); debug("created buffer at %#lx-%#lx", pBuf, (uintptr_t)pBuf + length); @@ -305,30 +302,34 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, if (m_Shared) return (void *)-ENOSYS; - if (vmm.CheckRegion(addr, Memory::G)) + int mRet = vma->Map(addr, pBuf, length, mFlags); + if (mRet < 0) { - debug("Address range %#lx-%#lx has a global page", - addr, (uintptr_t)addr + length); - // return (void *)-EINVAL; + debug("Failed to map file: %s", strerror(mRet)); + return (void *)(uintptr_t)mRet; } - - vmm.Map(addr, pBuf, length, mFlags); off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); fdt->_lseek(fildes, offset, SEEK_SET); ssize_t ret = fdt->_read(fildes, pBuf, length); - fdt->_lseek(fildes, oldOff, SEEK_SET); if (ret < 0) { debug("Failed to read file"); - return (void *)-ret; + return (void *)ret; } return addr; } else - vmm.Map(pBuf, pBuf, length, mFlags); + { + int mRet = vma->Map(pBuf, pBuf, length, mFlags); + if (mRet < 0) + { + debug("Failed to map file: %s", strerror(mRet)); + return (void *)(uintptr_t)mRet; + } + } off_t oldOff = fdt->_lseek(fildes, 0, SEEK_CUR); fdt->_lseek(fildes, offset, SEEK_SET); @@ -340,7 +341,7 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, if (ret < 0) { debug("Failed to read file"); - return (void *)-ret; + return (void *)ret; } return pBuf; } @@ -349,10 +350,9 @@ static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, return (void *)-ENOSYS; } - intptr_t ret = (intptr_t)vma->CreateCoWRegion(addr, length, - p_Read, p_Write, p_Exec, - m_Fixed, m_Shared); - + void *ret = vma->CreateCoWRegion(addr, length, + p_Read, p_Write, p_Exec, + m_Fixed, m_Shared); return (void *)ret; } #undef __FENNIX_KERNEL_SYSCALLS_LIST_H__ @@ -378,58 +378,56 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) i < uintptr_t(addr) + len; i += PAGE_SIZE) { - if (likely(!vmm.Check((void *)i, Memory::G))) - { - Memory::PageTableEntry *pte = vmm.GetPTE(addr); - if (pte == nullptr) - { - debug("Page %#lx is not mapped inside %#lx", - (void *)i, pcb->PageTable); - fixme("Page %#lx is not mapped", (void *)i); - continue; - return -ENOMEM; - } - - if (!pte->Present || - (!pte->UserSupervisor && p_Read) || - (!pte->ReadWrite && p_Write)) - { - debug("Page %p is not mapped with the correct permissions", - (void *)i); - return -EACCES; - } - - // pte->Present = !p_None; - pte->UserSupervisor = p_Read; - pte->ReadWrite = p_Write; - // pte->ExecuteDisable = p_Exec; - - debug("Changed permissions of page %#lx to %s %s %s %s", - (void *)i, - (prot & sc_PROT_NONE) ? "None" : "", - p_Read ? "Read" : "", - p_Write ? "Write" : "", - (prot & sc_PROT_EXEC) ? "Exec" : ""); - -#if defined(a64) - CPU::x64::invlpg(addr); -#elif defined(a32) - CPU::x32::invlpg(addr); -#elif defined(aa64) - asmv("dsb sy"); - asmv("tlbi vae1is, %0" - : - : "r"(addr) - : "memory"); - asmv("dsb sy"); - asmv("isb"); -#endif - } - else + if (unlikely(vmm.Check((void *)i, Memory::G))) { warn("%p is a global page", (void *)i); return -ENOMEM; } + + Memory::PageTableEntry *pte = vmm.GetPTE(addr); + if (pte == nullptr) + { + debug("Page %#lx is not mapped inside %#lx", + (void *)i, pcb->PageTable); + fixme("Page %#lx is not mapped", (void *)i); + continue; + return -ENOMEM; + } + + if (!pte->Present || + (!pte->UserSupervisor && p_Read) || + (!pte->ReadWrite && p_Write)) + { + debug("Page %p is not mapped with the correct permissions", + (void *)i); + return -EACCES; + } + + // pte->Present = !p_None; + pte->UserSupervisor = p_Read; + pte->ReadWrite = p_Write; + // pte->ExecuteDisable = p_Exec; + + debug("Changed permissions of page %#lx to %s %s %s %s", + (void *)i, + (prot & sc_PROT_NONE) ? "None" : "", + p_Read ? "Read" : "", + p_Write ? "Write" : "", + (prot & sc_PROT_EXEC) ? "Exec" : ""); + +#if defined(a64) + CPU::x64::invlpg(addr); +#elif defined(a32) + CPU::x32::invlpg(addr); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(addr) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif } return 0; @@ -446,21 +444,7 @@ static int linux_munmap(SysFrm *, void *addr, size_t length) PCB *pcb = thisProcess; Memory::VirtualMemoryArea *vma = pcb->vma; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); - - for (uintptr_t i = uintptr_t(addr); - i < uintptr_t(addr) + length; - i += PAGE_SIZE) - { - if (likely(!vmm.Check((void *)i, Memory::G))) - vmm.Remap((void *)i, (void *)i, Memory::P | Memory::RW); - else - warn("%p is a global page", (void *)i); - } - - /* TODO: Check if the page is allocated - and not only mapped */ - vma->FreePages((void *)addr, TO_PAGES(length) + 1); + vma->FreePages((void *)addr, TO_PAGES(length)); return 0; } @@ -478,14 +462,11 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)argp, Memory::US)) - { - debug("Invalid address %#lx", argp); + auto pArgp = vma->UserCheckAndGetAddress(argp); + if (pArgp == nullptr) return -EFAULT; - } - auto pArgp = pcb->PageTable->Get(argp); return fdt->_ioctl(fd, request, pArgp); } @@ -494,7 +475,11 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp) static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { PCB *pcb = thisProcess; - const struct iovec *pIov = pcb->PageTable->Get(iov); + Memory::VirtualMemoryArea *vma = pcb->vma; + + const struct iovec *pIov = vma->UserCheckAndGetAddress(iov, sizeof(struct iovec) * iovcnt); + if (pIov == nullptr) + return -EFAULT; ssize_t Total = 0; for (int i = 0; i < iovcnt; i++) @@ -533,7 +518,11 @@ static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { PCB *pcb = thisProcess; - const struct iovec *pIov = pcb->PageTable->Get(iov); + Memory::VirtualMemoryArea *vma = pcb->vma; + + const struct iovec *pIov = vma->UserCheckAndGetAddress(iov, sizeof(struct iovec) * iovcnt); + if (pIov == nullptr) + return -EFAULT; ssize_t Total = 0; for (int i = 0; i < iovcnt; i++) @@ -572,10 +561,14 @@ static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int static int linux_access(SysFrm *, const char *pathname, int mode) { PCB *pcb = thisProcess; - auto pPathname = pcb->PageTable->Get(pathname); + Memory::VirtualMemoryArea *vma = pcb->vma; + + auto pPathname = vma->UserCheckAndGetAddress(pathname); + if (pPathname == nullptr) + return -EFAULT; stub; - debug("access(%s, %d)", (char *)pPathname, mode); + fixme("access(%s, %d)", (char *)pPathname, mode); return 0; } @@ -583,7 +576,9 @@ static int linux_access(SysFrm *, const char *pathname, int mode) static int linux_pipe(SysFrm *, int pipefd[2]) { PCB *pcb = thisProcess; - int *pPipefd = pcb->PageTable->Get(pipefd); + Memory::VirtualMemoryArea *vma = pcb->vma; + + int *pPipefd = vma->UserCheckAndGetAddress(pipefd); debug("pipefd=%#lx", pPipefd); fixme("pipefd=[%d, %d]", pPipefd[0], pPipefd[1]); return -ENOSYS; @@ -618,22 +613,12 @@ static int linux_nanosleep(SysFrm *, struct timespec *rem) { PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)req, Memory::US)) - { - debug("Invalid address %#lx", req); + auto pReq = vma->UserCheckAndGetAddress(req); + auto pRem = vma->UserCheckAndGetAddress(rem); + if (pReq == nullptr || pRem == nullptr) return -EFAULT; - } - - if (rem && !vmm.Check((void *)rem, Memory::US)) - { - debug("Invalid address %#lx", rem); - return -EFAULT; - } - - auto pReq = pcb->PageTable->Get(req); - auto pRem = rem ? pcb->PageTable->Get(rem) : 0; if (pReq->tv_nsec < 0 || pReq->tv_nsec > 999999999) { @@ -711,7 +696,7 @@ static pid_t linux_fork(SysFrm *sf) } NewProcess->PageTable = Parent->PageTable->Fork(); - NewProcess->vma->SetTable(NewProcess->PageTable); + NewProcess->vma->Table = NewProcess->PageTable; NewProcess->vma->Fork(Parent->vma); NewProcess->ProgramBreak->SetTable(NewProcess->PageTable); NewProcess->FileDescriptors->Fork(Parent->FileDescriptors); @@ -778,64 +763,36 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn /* FIXME: exec doesn't follow the UNIX standard The pid, open files, etc. should be preserved */ PCB *pcb = thisProcess; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (pathname == nullptr || - !vmm.Check((void *)pathname, Memory::US) || - !vmm.Check((void *)argv, Memory::US) || - !vmm.Check((void *)envp, Memory::US)) - return -ENOENT; - - if (!vmm.Check((void *)pathname, Memory::US)) - { - debug("Invalid address %#lx", pathname); + auto pPathname = vma->UserCheckAndGetAddress(pathname, PAGE_SIZE); + auto pArgv = vma->UserCheckAndGetAddress(argv, 1/*MAX_ARG*/); /* MAX_ARG is too much? */ + auto pEnvp = vma->UserCheckAndGetAddress(envp, 1/*MAX_ARG*/); + if (pPathname == nullptr || pArgv == nullptr || pEnvp == nullptr) return -EFAULT; - } - - if (!vmm.Check((void *)argv, Memory::US)) - { - debug("Invalid address %#lx", argv); - return -EFAULT; - } - - if (!vmm.Check((void *)envp, Memory::US)) - { - debug("Invalid address %#lx", envp); - return -EFAULT; - } - - auto pPathname = pcb->PageTable->Get(pathname); - auto pArgv = pcb->PageTable->Get(argv); - auto pEnvp = pcb->PageTable->Get(envp); function("%s %#lx %#lx", pPathname, pArgv, pEnvp); int argvLen = 0; for (argvLen = 0; MAX_ARG; argvLen++) { + if (vma->UserCheck(pArgv[argvLen]) < 0) + break; + auto arg = pcb->PageTable->Get(pArgv[argvLen]); if (arg == nullptr) break; - - if (!vmm.Check((void *)arg, Memory::US)) - { - debug("Invalid address %#lx", arg); - return -EFAULT; - } } int envpLen = 0; for (envpLen = 0; MAX_ARG; envpLen++) { + if (vma->UserCheck(pEnvp[envpLen]) < 0) + break; + auto arg = pcb->PageTable->Get(pEnvp[envpLen]); if (arg == nullptr) break; - - if (!vmm.Check((void *)arg, Memory::US)) - { - debug("Invalid address %#lx", arg); - return -EFAULT; - } } char **safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(argvLen * sizeof(char *))); @@ -1011,13 +968,7 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, inefficient and should be rewritten */ PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - - if (!vmm.Check(rusage, Memory::US) && rusage != nullptr) - { - debug("Invalid address %#lx", rusage); - return -EFAULT; - } + Memory::VirtualMemoryArea *vma = pcb->vma; if (pid == -1) { @@ -1052,7 +1003,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, size_t uTime = child->Info.UserTime; size_t _maxrss = child->GetSize(); - struct rusage *pRusage = pcb->PageTable->Get(rusage); + struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage); + if (pRusage == nullptr) + return -EFAULT; pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ @@ -1071,7 +1024,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, { if (wstatus != nullptr) { - int *pWstatus = pcb->PageTable->Get(wstatus); + int *pWstatus = vma->UserCheckAndGetAddress(wstatus); + if (pWstatus == nullptr) + return -EFAULT; *pWstatus = 0; bool ProcessExited = true; @@ -1098,7 +1053,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, size_t uTime = child->Info.UserTime; size_t _maxrss = child->GetSize(); - struct rusage *pRusage = pcb->PageTable->Get(rusage); + struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage); + if (pRusage == nullptr) + return -EFAULT; pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ @@ -1172,7 +1129,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, if (wstatus != nullptr) { - int *pWstatus = pcb->PageTable->Get(wstatus); + int *pWstatus = vma->UserCheckAndGetAddress(wstatus); + if (pWstatus == nullptr) + return -EFAULT; *pWstatus = 0; bool ProcessExited = true; @@ -1211,7 +1170,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, size_t uTime = tPcb->Info.UserTime; size_t _maxrss = tPcb->GetSize(); - struct rusage *pRusage = pcb->PageTable->Get(rusage); + struct rusage *pRusage = vma->UserCheckAndGetAddress(rusage); + if (pRusage == nullptr) + return -EFAULT; pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ @@ -1265,15 +1226,11 @@ static int linux_uname(SysFrm *, struct utsname *buf) assert(sizeof(struct utsname) < PAGE_SIZE); PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check(buf, Memory::US)) - { - debug("Invalid address %#lx", buf); + auto pBuf = vma->UserCheckAndGetAddress(buf); + if (pBuf == nullptr) return -EFAULT; - } - - auto pBuf = pcb->PageTable->Get(buf); struct utsname uname = { @@ -1337,11 +1294,11 @@ static int linux_uname(SysFrm *, struct utsname *buf) return 0; } +/* https://man7.org/linux/man-pages/man2/fcntl.2.html */ static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); switch (cmd) { @@ -1386,9 +1343,13 @@ static int linux_creat(SysFrm *, const char *pathname, mode_t mode) static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) { PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; fixme("semi-stub"); - const char *pPathname = pcb->PageTable->Get(pathname); + const char *pPathname = vma->UserCheckAndGetAddress(pathname); + if (!pPathname) + return -EFAULT; + vfs::Node *n = fs->Create(pPathname, vfs::DIRECTORY, pcb->CurrentWorkingDirectory); if (!n) return -EEXIST; @@ -1409,15 +1370,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname, } PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - if (!vmm.Check((void *)buf, Memory::US)) - { - warn("Invalid address %#lx", buf); - return -EFAULT; - } + Memory::VirtualMemoryArea *vma = pcb->vma; + + const char *pPath = vma->UserCheckAndGetAddress(pathname); + char *pBuf = vma->UserCheckAndGetAddress(buf); + if (pPath == nullptr || pBuf == nullptr) + return -EFAULT; - const char *pPath = pcb->PageTable->Get(pathname); - char *pBuf = pcb->PageTable->Get(buf); function("%s %#lx %ld", pPath, buf, bufsiz); vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; int fd = fdt->_open(pPath, O_RDONLY, 0); @@ -1479,19 +1438,10 @@ static pid_t linux_getppid(SysFrm *) static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) { PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check((void *)addr)) - { - debug("Invalid address %#lx", addr); + if (vma->UserCheck(addr) < 0) return -EFAULT; - } - - if (!vmm.Check((void *)addr, Memory::US)) - { - debug("Address %#lx is not user accessible", addr); - return -EPERM; - } switch (code) { @@ -1577,6 +1527,7 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) } PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; debug("cmd=%#x arg=%#lx", cmd, arg); switch ((unsigned int)cmd) @@ -1610,14 +1561,10 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) } case LINUX_REBOOT_CMD_RESTART2: { - Memory::Virtual vmm(pcb->PageTable); - if (!vmm.Check(arg, Memory::US)) - { - debug("Invalid address %#lx", arg); + void *pArg = vma->__UserCheckAndGetAddress(arg, sizeof(void *)); + if (pArg == nullptr) return -EFAULT; - } - void *pArg = pcb->PageTable->Get(arg); KPrint("Restarting system with command '%s'", (const char *)pArg); @@ -1656,24 +1603,17 @@ static int linux_sigaction(SysFrm *, int signum, } PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - - if (oldact && !vmm.Check(oldact, Memory::US)) - { - debug("Invalid address %#lx", oldact); - return -EFAULT; - } - - if (act && !vmm.Check((void *)act, Memory::US)) - { - debug("Invalid address %#lx", act); - return -EFAULT; - } + Memory::VirtualMemoryArea *vma = pcb->vma; debug("signum=%d act=%#lx oldact=%#lx", signum, act, oldact); - auto pOldact = pcb->PageTable->Get(oldact); + if (vma->UserCheck(act) < 0 && act != nullptr) + return -EFAULT; + if (vma->UserCheck(oldact) < 0 && oldact != nullptr) + return -EFAULT; + auto pAct = pcb->PageTable->Get(act); + auto pOldact = pcb->PageTable->Get(oldact); int ret = 0; if (pOldact) @@ -1701,6 +1641,13 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set, } PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + + if (vma->UserCheck(set) < 0 && set != nullptr) + return -EFAULT; + if (vma->UserCheck(oldset) < 0 && oldset != nullptr) + return -EFAULT; + const sigset_t *pSet = (const sigset_t *)pcb->PageTable->Get((void *)set); sigset_t *pOldset = (sigset_t *)pcb->PageTable->Get(oldset); @@ -1761,6 +1708,7 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, { PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + Memory::VirtualMemoryArea *vma = pcb->vma; if (count < sizeof(struct linux_dirent64)) { @@ -1783,7 +1731,10 @@ static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, return -ENOTDIR; } - auto pDirp = pcb->PageTable->Get(dirp); + auto pDirp = vma->UserCheckAndGetAddress(dirp); + if (pDirp == nullptr) + return -EFAULT; + UNUSED(pDirp); stub; return -ENOSYS; @@ -1795,15 +1746,11 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) static_assert(sizeof(struct timespec) < PAGE_SIZE); PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (!vmm.Check(tp, Memory::US)) - { - debug("Invalid address %#lx", tp); + timespec *pTp = vma->UserCheckAndGetAddress(tp); + if (pTp == nullptr) return -EFAULT; - } - - timespec *pTp = pcb->PageTable->Get(tp); /* FIXME: This is not correct? */ switch (clockid) @@ -1875,23 +1822,11 @@ static long linux_newfstatat(SysFrm *, int dfd, const char *filename, PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; if (flag) fixme("flag %#x is stub", flag); - if (!filename) - { - debug("Invalid filename %#lx", filename); - return -EFAULT; - } - - if (!statbuf) - { - debug("Invalid statbuf %#lx", statbuf); - return -EFAULT; - } - if (dfd == AT_FDCWD) { fixme("dfd AT_FDCWD is stub"); @@ -1906,8 +1841,10 @@ static long linux_newfstatat(SysFrm *, int dfd, const char *filename, return -EBADF; } - const char *pFilename = pcb->PageTable->Get(filename); - struct stat *pStatbuf = pcb->PageTable->Get(statbuf); + const char *pFilename = vma->UserCheckAndGetAddress(filename); + struct stat *pStatbuf = vma->UserCheckAndGetAddress(statbuf); + if (pFilename == nullptr || pStatbuf == nullptr) + return -EFAULT; debug("%s %#lx %#lx", pFilename, filename, statbuf); return fdt->_stat(pFilename, pStatbuf); @@ -1920,7 +1857,12 @@ static int linux_pipe2(SysFrm *sf, int pipefd[2], int flags) return linux_pipe(sf, pipefd); PCB *pcb = thisProcess; - int *pPipefd = pcb->PageTable->Get(pipefd); + Memory::VirtualMemoryArea *vma = pcb->vma; + + int *pPipefd = vma->UserCheckAndGetAddress(pipefd); + if (pPipefd == nullptr) + return -EFAULT; + debug("pipefd=%#lx", pPipefd); fixme("pipefd=[%d, %d] flags=%#x", pPipefd[0], pPipefd[1], flags); return -ENOSYS; @@ -1934,22 +1876,15 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource, static_assert(sizeof(struct rlimit) < PAGE_SIZE); PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Memory::VirtualMemoryArea *vma = pcb->vma; - if (old_limit && !vmm.Check(old_limit, Memory::US)) - { - debug("Invalid address %#lx", old_limit); + auto pOldLimit = vma->UserCheckAndGetAddress(old_limit); + auto pNewLimit = vma->UserCheckAndGetAddress(new_limit); + if (pOldLimit == nullptr && old_limit != nullptr) return -EFAULT; - } - if (new_limit && !vmm.Check((void *)new_limit, Memory::US)) - { - debug("Invalid address %#lx", new_limit); + if (pNewLimit == nullptr && new_limit != nullptr) return -EFAULT; - } - - auto pOldLimit = pcb->PageTable->Get(old_limit); - auto pNewLimit = pcb->PageTable->Get(new_limit); UNUSED(pOldLimit); UNUSED(pNewLimit); @@ -1992,13 +1927,7 @@ static ssize_t linux_getrandom(SysFrm *, void *buf, size_t buflen, unsigned int flags) { PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); - - if (!vmm.Check(buf, Memory::US)) - { - debug("Invalid address %#lx", buf); - return -EFAULT; - } + Memory::VirtualMemoryArea *vma = pcb->vma; if (flags & GRND_NONBLOCK) fixme("GRND_NONBLOCK not implemented"); @@ -2011,6 +1940,10 @@ static ssize_t linux_getrandom(SysFrm *, void *buf, return -EINVAL; } + auto pBuf = vma->UserCheckAndGetAddress(buf, buflen); + if (pBuf == nullptr) + return -EFAULT; + if (flags & GRND_RANDOM) { uint16_t random; @@ -2019,7 +1952,7 @@ static ssize_t linux_getrandom(SysFrm *, void *buf, random = Random::rand16(); { Memory::SwapPT swap(pcb->PageTable); - ((uint8_t *)buf)[i] = uint8_t(random & 0xFF); + ((uint8_t *)pBuf)[i] = uint8_t(random & 0xFF); } } return buflen; diff --git a/tasking/thread.cpp b/tasking/thread.cpp index a18100b..eda9944 100644 --- a/tasking/thread.cpp +++ b/tasking/thread.cpp @@ -454,7 +454,7 @@ namespace Tasking else this->SetState(Ready); - this->vma = new Memory::VirtualMemoryArea(this->Parent->PageTable); + this->vma = this->Parent->vma; #if defined(a64) this->Registers.rip = EntryPoint; @@ -507,13 +507,13 @@ namespace Tasking { this->Stack = new Memory::StackGuard(true, this->vma); - gsTCB *gsT = (gsTCB *)this->vma->RequestPages(TO_PAGES(sizeof(gsTCB))); + gsTCB *gsT = (gsTCB *)this->vma->RequestPages(TO_PAGES(sizeof(gsTCB)), false, true); #ifdef DEBUG gsT->__stub = 0xFFFFFFFFFFFFFFFF; #endif gsT->ScPages = TO_PAGES(STACK_SIZE); - gsT->SyscallStackBase = this->vma->RequestPages(gsT->ScPages); + gsT->SyscallStackBase = this->vma->RequestPages(gsT->ScPages, false, true); gsT->SyscallStack = (void *)((uintptr_t)gsT->SyscallStackBase + STACK_SIZE - 0x10); debug("New syscall stack created: %#lx (base: %#lx) with gs base at %#lx", gsT->SyscallStack, gsT->SyscallStackBase, gsT); @@ -641,9 +641,6 @@ namespace Tasking /* Free CPU Stack */ delete this->Stack; - /* Free all allocated memory */ - delete this->vma; - /* Free Name */ delete[] this->Name;