fix: various kernel bug fixes

This commit is contained in:
2026-04-10 23:16:02 +02:00
parent 0433274244
commit fd7fcbbbc8
12 changed files with 282 additions and 163 deletions
+36 -13
View File
@@ -20,11 +20,11 @@ namespace Montauk {
static constexpr int MaxHeapAllocs = 512;
static HeapAlloc g_heapAllocs[Sched::MaxProcesses][MaxHeapAllocs];
static int g_heapAllocCount[Sched::MaxProcesses];
inline HeapAlloc g_heapAllocs[Sched::MaxProcesses][MaxHeapAllocs] = {};
inline int g_heapAllocCount[Sched::MaxProcesses] = {};
// Get the process table slot index for the current process
static int GetCurrentSlot() {
inline int GetCurrentSlot() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
// Process slot index = pointer offset from slot 0
@@ -32,9 +32,11 @@ namespace Montauk {
return (int)(proc - slot0);
}
static uint64_t Sys_Alloc(uint64_t size) {
inline uint64_t Sys_Alloc(uint64_t size) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
int slot = GetCurrentSlot();
if (slot < 0) return 0;
// Guard against overflow before rounding
static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL;
@@ -50,36 +52,57 @@ namespace Montauk {
if (userVa + size < userVa || userVa + size > USER_SPACE_END) return 0;
uint64_t numPages = size / 0x1000;
if (g_heapAllocCount[slot] >= MaxHeapAllocs) return 0;
// Allocate physical pages and map them into the process
uint64_t mappedPages = 0;
for (uint64_t i = 0; i < numPages; i++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return 0;
if (page == nullptr) {
for (uint64_t j = 0; j < mappedPages; j++) {
uint64_t pageVa = userVa + j * 0x1000;
uint64_t physAddr = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, pageVa);
if (physAddr != 0) {
Memory::g_pfa->Free((void*)Memory::HHDM(physAddr));
}
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, pageVa);
}
return 0;
}
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
if (!Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa + i * 0x1000)) return 0;
if (!Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa + i * 0x1000)) {
Memory::g_pfa->Free(page);
for (uint64_t j = 0; j < mappedPages; j++) {
uint64_t pageVa = userVa + j * 0x1000;
uint64_t mappedPhys = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, pageVa);
if (mappedPhys != 0) {
Memory::g_pfa->Free((void*)Memory::HHDM(mappedPhys));
}
Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, pageVa);
}
return 0;
}
mappedPages++;
}
proc->heapNext += size;
// Track the allocation so Sys_Free can release it
int slot = GetCurrentSlot();
if (slot >= 0) Sched::g_allocatedPages[slot] += numPages;
if (slot >= 0 && g_heapAllocCount[slot] < MaxHeapAllocs) {
g_heapAllocs[slot][g_heapAllocCount[slot]++] = { userVa, numPages };
}
Sched::g_allocatedPages[slot] += numPages;
g_heapAllocs[slot][g_heapAllocCount[slot]++] = { userVa, numPages };
return userVa;
}
// Reset heap allocation tracking for a process slot.
// The actual physical pages are freed by Paging::FreeUserHalf() during process cleanup.
static void CleanupHeapForSlot(int slot, uint64_t /*pml4Phys*/) {
inline void CleanupHeapForSlot(int slot, uint64_t /*pml4Phys*/) {
if (slot < 0 || slot >= Sched::MaxProcesses) return;
g_heapAllocCount[slot] = 0;
Sched::g_allocatedPages[slot] = 0;
}
static void Sys_Free(uint64_t addr) {
inline void Sys_Free(uint64_t addr) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return;
+9 -9
View File
@@ -18,7 +18,7 @@ namespace Montauk {
// Maximum libraries per process
static constexpr int MaxLibsPerProcess = 8;
static constexpr int MaxProcesses = 64;
static constexpr int MaxProcesses = Sched::MaxProcesses;
// Library entry tracking
struct LibEntry {
@@ -28,15 +28,15 @@ namespace Montauk {
bool inUse;
};
static uint64_t GetLibSlotBase(int libSlot) {
inline uint64_t GetLibSlotBase(int libSlot) {
return Sched::LIB_BASE + (uint64_t(libSlot) * Sched::LIB_MAX_SIZE);
}
// Per-process library table
static LibEntry g_libTable[MaxProcesses][MaxLibsPerProcess];
inline LibEntry g_libTable[MaxProcesses][MaxLibsPerProcess] = {};
// Initialize library table for a process slot
static void InitLibTable(int slot) {
inline void InitLibTable(int slot) {
if (slot < 0 || slot >= MaxProcesses) return;
for (int i = 0; i < MaxLibsPerProcess; i++) {
g_libTable[slot][i].inUse = false;
@@ -49,7 +49,7 @@ namespace Montauk {
// Load a shared library into the current process's address space.
// Returns a library handle (slot index + 1) on success, or 0 on failure.
// The library is loaded at a fixed address based on the slot.
static uint64_t Sys_LoadLib(const char* path) {
inline uint64_t Sys_LoadLib(const char* path) {
int slot = GetCurrentSlot();
if (slot < 0) return 0;
@@ -100,7 +100,7 @@ namespace Montauk {
// Unload a shared library.
// Decrements refcount; actually unmaps when refcount reaches 0.
static int Sys_UnloadLib(uint64_t handle) {
inline int Sys_UnloadLib(uint64_t handle) {
int slot = GetCurrentSlot();
if (slot < 0) return -1;
@@ -139,7 +139,7 @@ namespace Montauk {
// handle = library handle from LoadLib
// symbolOffset = ELF symbol value from the library's symbol table
// Returns the virtual address of the symbol, or 0 if not found.
static uint64_t Sys_DLSym(uint64_t handle, uint64_t symbolOffset) {
inline uint64_t Sys_DLSym(uint64_t handle, uint64_t symbolOffset) {
int slot = GetCurrentSlot();
if (slot < 0) return 0;
@@ -153,7 +153,7 @@ namespace Montauk {
}
// Get library relocation base / load bias (for userspace symbol resolution)
static uint64_t Sys_GetLibBase(uint64_t handle) {
inline uint64_t Sys_GetLibBase(uint64_t handle) {
int slot = GetCurrentSlot();
if (slot < 0) return 0;
@@ -166,7 +166,7 @@ namespace Montauk {
}
// Cleanup library table for a process slot
static void CleanupLibTable(int slot) {
inline void CleanupLibTable(int slot) {
if (slot < 0 || slot >= MaxProcesses) return;
auto* proc = Sched::GetProcessSlot(slot);
+4
View File
@@ -11,6 +11,7 @@
#include <Fs/FsProbe.hpp>
#include <Fs/Fat32.hpp>
#include <Fs/Ext2.hpp>
#include <Api/UserMemory.hpp>
#include "Syscall.hpp"
@@ -25,6 +26,7 @@ namespace Montauk {
// Fill a user buffer with partition info. Returns the number of entries written.
static int Sys_PartList(PartInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(PartInfo), true)) return -1;
int total = Drivers::Storage::Gpt::GetPartitionCount();
int count = total < maxCount ? total : maxCount;
@@ -61,6 +63,7 @@ namespace Montauk {
if (!dev) return -1;
if (lba + count > dev->SectorCount) return -1;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, true)) return -1;
if (!dev->ReadSectors(dev->Ctx, lba, count, buffer)) return -1;
@@ -76,6 +79,7 @@ namespace Montauk {
if (!dev) return -1;
if (lba + count > dev->SectorCount) return -1;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, false)) return -1;
if (!dev->WriteSectors(dev->Ctx, lba, count, buffer)) return -1;
+112 -112
View File
@@ -36,40 +36,25 @@
#include "LibSyscall.hpp" // SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM
#include "CrashReportSyscall.hpp" // SYS_CRASH_REPORT
#include "Clipboard.hpp" // SYS_CLIPBOARD_*
#include "UserMemory.hpp"
// Assembly entry point
extern "C" void SyscallEntry();
namespace Montauk {
// ---- User pointer validation ----
// Reject pointers that fall in the kernel-half of the address space
// (canonical high addresses, i.e. >= 0x0000800000000000).
// This prevents userspace from tricking the kernel into reading/writing
// kernel memory via syscall arguments.
static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL;
static bool IsUserPtr(uint64_t addr) {
return addr == 0 || addr < USER_SPACE_END;
}
// Validate that a pointer is non-null and in user space
static bool ValidUserPtr(uint64_t addr) {
return addr != 0 && addr < USER_SPACE_END;
}
static constexpr uint64_t kMaxPrintableStringBytes = 4096;
static constexpr uint64_t kMaxPathBytes = 256;
static constexpr uint64_t kMaxArgsBytes = 256;
static constexpr uint64_t kMaxWindowTitleBytes = 256;
static constexpr uint64_t kMaxHostnameBytes = 256;
static constexpr uint64_t kMaxUserNameBytes = 32;
// ---- Dispatch ----
extern "C" int64_t SyscallDispatch(SyscallFrame* frame) {
switch (frame->syscall_nr) {
case SYS_EXIT: {
int slot = GetCurrentSlot();
auto* proc = Sched::GetCurrentProcessPtr();
if (slot >= 0 && proc)
CleanupHeapForSlot(slot, proc->pml4Phys);
if (slot >= 0)
CleanupLibTable(slot);
Sys_Exit((int)frame->arg1);
return 0;
}
@@ -82,17 +67,17 @@ namespace Montauk {
case SYS_GETPID:
return (int64_t)Sys_GetPid();
case SYS_PRINT:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPrintableStringBytes)) return -1;
Sys_Print((const char*)frame->arg1);
return 0;
case SYS_PUTCHAR:
Sys_Putchar((char)frame->arg1);
return 0;
case SYS_OPEN:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
return (int64_t)Sys_Open((const char*)frame->arg1);
case SYS_READ:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg4, true)) return -1;
return (int64_t)Sys_Read((int)frame->arg1, (uint8_t*)frame->arg2,
frame->arg3, frame->arg4);
case SYS_GETSIZE:
@@ -101,7 +86,13 @@ namespace Montauk {
Sys_Close((int)frame->arg1);
return 0;
case SYS_READDIR:
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg2)) return -1;
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::Range(frame->arg2,
(uint64_t)((frame->arg3 > 256) ? 256 : frame->arg3) * sizeof(const char*),
true)) {
return -1;
}
return (int64_t)Sys_ReadDir((const char*)frame->arg1,
(const char**)frame->arg2,
(int)frame->arg3);
@@ -115,13 +106,13 @@ namespace Montauk {
case SYS_GETMILLISECONDS:
return (int64_t)Sys_GetMilliseconds();
case SYS_GETINFO:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<SysInfo>(frame->arg1)) return -1;
Sys_GetInfo((SysInfo*)frame->arg1);
return 0;
case SYS_ISKEYAVAILABLE:
return (int64_t)Sys_IsKeyAvailable();
case SYS_GETKEY:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<KeyEvent>(frame->arg1)) return -1;
Sys_GetKey((KeyEvent*)frame->arg1);
return 0;
case SYS_GETCHAR:
@@ -129,14 +120,15 @@ namespace Montauk {
case SYS_PING:
return (int64_t)Sys_Ping((uint32_t)frame->arg1, (uint32_t)frame->arg2);
case SYS_SPAWN:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
return (int64_t)Sys_Spawn((const char*)frame->arg1,
IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
case SYS_WAITPID:
Sys_WaitPid((int)frame->arg1);
return 0;
case SYS_FBINFO:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<FbInfo>(frame->arg1)) return -1;
Sys_FbInfo((FbInfo*)frame->arg1);
return 0;
case SYS_FBMAP:
@@ -144,7 +136,7 @@ namespace Montauk {
case SYS_TERMSIZE:
return (int64_t)Sys_TermSize();
case SYS_GETARGS:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
return (int64_t)Sys_GetArgs((char*)frame->arg1, frame->arg2);
case SYS_RESET:
Sys_Reset();
@@ -153,7 +145,7 @@ namespace Montauk {
Sys_Shutdown();
return 0;
case SYS_GETTIME:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<DateTime>(frame->arg1)) return -1;
Sys_GetTime((DateTime*)frame->arg1);
return 0;
case SYS_SOCKET:
@@ -167,87 +159,94 @@ namespace Montauk {
case SYS_ACCEPT:
return (int64_t)Sys_Accept((int)frame->arg1);
case SYS_SEND:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
return (int64_t)Sys_Send((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_RECV:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
return (int64_t)Sys_Recv((int)frame->arg1, (uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_CLOSESOCK:
Sys_CloseSock((int)frame->arg1);
return 0;
case SYS_GETNETCFG:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<NetCfg>(frame->arg1)) return -1;
Sys_GetNetCfg((NetCfg*)frame->arg1);
return 0;
case SYS_SETNETCFG:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Readable<NetCfg>(frame->arg1)) return -1;
return (int64_t)Sys_SetNetCfg((const NetCfg*)frame->arg1);
case SYS_SENDTO:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
return (int64_t)Sys_SendTo((int)frame->arg1, (const uint8_t*)frame->arg2,
(uint32_t)frame->arg3, (uint32_t)frame->arg4,
(uint16_t)frame->arg5);
case SYS_RECVFROM:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
if (!UserMemory::OptionalRange(frame->arg4, sizeof(uint32_t), true)) return -1;
if (!UserMemory::OptionalRange(frame->arg5, sizeof(uint16_t), true)) return -1;
return (int64_t)Sys_RecvFrom((int)frame->arg1, (uint8_t*)frame->arg2,
(uint32_t)frame->arg3,
IsUserPtr(frame->arg4) ? (uint32_t*)frame->arg4 : nullptr,
IsUserPtr(frame->arg5) ? (uint16_t*)frame->arg5 : nullptr);
UserMemory::IsUserPtr(frame->arg4) ? (uint32_t*)frame->arg4 : nullptr,
UserMemory::IsUserPtr(frame->arg5) ? (uint16_t*)frame->arg5 : nullptr);
case SYS_FWRITE:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg4, false)) return -1;
return (int64_t)Sys_FWrite((int)frame->arg1, (const uint8_t*)frame->arg2,
frame->arg3, frame->arg4);
case SYS_FCREATE:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
return (int64_t)Sys_FCreate((const char*)frame->arg1);
case SYS_FDELETE:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
return (int64_t)Sys_FDelete((const char*)frame->arg1);
case SYS_FMKDIR:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
return (int64_t)Sys_FMkdir((const char*)frame->arg1);
case SYS_FRENAME:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg2, kMaxPathBytes)) return -1;
return (int64_t)Sys_FRename((const char*)frame->arg1, (const char*)frame->arg2);
case SYS_DRIVELIST:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(int), true)) return -1;
return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
case SYS_TERMSCALE:
return Sys_TermScale(frame->arg1, frame->arg2);
case SYS_RESOLVE:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxHostnameBytes)) return -1;
return Sys_Resolve((const char*)frame->arg1);
case SYS_GETRANDOM:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
return Sys_GetRandom((uint8_t*)frame->arg1, frame->arg2);
case SYS_KLOG:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
return Kt::ReadKernelLog((char*)frame->arg1, frame->arg2);
case SYS_MOUSESTATE:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<MouseState>(frame->arg1)) return -1;
Sys_MouseState((MouseState*)frame->arg1);
return 0;
case SYS_SETMOUSEBOUNDS:
Sys_SetMouseBounds((int32_t)frame->arg1, (int32_t)frame->arg2);
return 0;
case SYS_SPAWN_REDIR:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
return (int64_t)Sys_SpawnRedir((const char*)frame->arg1,
IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
case SYS_CHILDIO_READ:
if (!ValidUserPtr(frame->arg2)) return -1;
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
return (int64_t)Sys_ChildIoRead((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
case SYS_CHILDIO_WRITE:
if (!ValidUserPtr(frame->arg2)) return -1;
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
return (int64_t)Sys_ChildIoWrite((int)frame->arg1, (const char*)frame->arg2, (int)frame->arg3);
case SYS_CHILDIO_WRITEKEY:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Readable<KeyEvent>(frame->arg2)) return -1;
return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEvent*)frame->arg2);
case SYS_CHILDIO_SETTERMSZ:
return (int64_t)Sys_ChildIoSetTermsz((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_WINCREATE:
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg4)) return -1;
if (!UserMemory::String(frame->arg1, kMaxWindowTitleBytes)) return -1;
if (!UserMemory::Writable<WinCreateResult>(frame->arg4)) return -1;
return (int64_t)Sys_WinCreate((const char*)frame->arg1, (int)frame->arg2,
(int)frame->arg3, (WinCreateResult*)frame->arg4);
case SYS_WINDESTROY:
@@ -255,39 +254,33 @@ namespace Montauk {
case SYS_WINPRESENT:
return (int64_t)Sys_WinPresent((int)frame->arg1);
case SYS_WINPOLL:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Writable<WinEvent>(frame->arg2)) return -1;
return (int64_t)Sys_WinPoll((int)frame->arg1, (WinEvent*)frame->arg2);
case SYS_WINENUM:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(WinInfo), true)) return -1;
return (int64_t)Sys_WinEnum((WinInfo*)frame->arg1, (int)frame->arg2);
case SYS_WINMAP:
return (int64_t)Sys_WinMap((int)frame->arg1);
case SYS_WINUNMAP:
return (int64_t)Sys_WinUnmap((int)frame->arg1);
case SYS_WINSENDEVENT:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Readable<WinEvent>(frame->arg2)) return -1;
return (int64_t)Sys_WinSendEvent((int)frame->arg1, (const WinEvent*)frame->arg2);
case SYS_WINRESIZE:
return (int64_t)Sys_WinResize((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_PROCLIST:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(ProcInfo), true)) return -1;
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
case SYS_KILL: {
// Free heap allocations for the target process before killing it
auto* target = Sched::GetProcessByPid((int)frame->arg1);
if (target) {
auto* slot0 = Sched::GetProcessSlot(0);
int targetSlot = (int)(target - slot0);
CleanupHeapForSlot(targetSlot, target->pml4Phys);
CleanupLibTable(targetSlot);
}
case SYS_KILL:
return (int64_t)Sys_Kill((int)frame->arg1);
}
case SYS_DEVLIST:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return -1;
return (int64_t)Sys_DevList((DevInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISKINFO:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<DiskInfo>(frame->arg1)) return -1;
return (int64_t)Sys_DiskInfo((DiskInfo*)frame->arg1, (int)frame->arg2);
case SYS_WINSETSCALE:
return (int64_t)Sys_WinSetScale((int)frame->arg1);
@@ -296,53 +289,54 @@ namespace Montauk {
case SYS_WINSETCURSOR:
return (int64_t)Sys_WinSetCursor((int)frame->arg1, (int)frame->arg2);
case SYS_MEMSTATS:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<MemStats>(frame->arg1)) return -1;
Sys_MemStats((MemStats*)frame->arg1);
return 0;
case SYS_PARTLIST:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(PartInfo), true)) return -1;
return (int64_t)Sys_PartList((PartInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISKREAD:
if (!ValidUserPtr(frame->arg4)) return -1;
return (int64_t)Sys_DiskRead((int)frame->arg1, frame->arg2,
(uint32_t)frame->arg3, (void*)frame->arg4);
case SYS_DISKWRITE:
if (!ValidUserPtr(frame->arg4)) return -1;
return (int64_t)Sys_DiskWrite((int)frame->arg1, frame->arg2,
(uint32_t)frame->arg3, (const void*)frame->arg4);
case SYS_GPTINIT:
return (int64_t)Sys_GptInit((int)frame->arg1);
case SYS_GPTADD:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Readable<GptAddParams>(frame->arg1)) return -1;
return (int64_t)Sys_GptAdd((const GptAddParams*)frame->arg1);
case SYS_FSMOUNT:
return (int64_t)Sys_FsMount((int)frame->arg1, (int)frame->arg2);
case SYS_FSFORMAT:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Readable<FsFormatParams>(frame->arg1)) return -1;
return (int64_t)Sys_FsFormat((const FsFormatParams*)frame->arg1);
case SYS_AUDIOOPEN:
return Sys_AudioOpen((uint32_t)frame->arg1, (uint8_t)frame->arg2, (uint8_t)frame->arg3);
case SYS_AUDIOCLOSE:
return Sys_AudioClose((int)frame->arg1);
case SYS_AUDIOWRITE:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
return Sys_AudioWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_AUDIOCTL:
return Sys_AudioCtl((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_BTSCAN:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtScanResult), true)) return -1;
return Sys_BtScan((BtScanResult*)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
case SYS_BTCONNECT:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
return Sys_BtConnect((const uint8_t*)frame->arg1);
case SYS_BTDISCONNECT:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
return Sys_BtDisconnect((const uint8_t*)frame->arg1);
case SYS_BTLIST:
if (!ValidUserPtr(frame->arg1)) return -1;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtDevInfo), true)) return -1;
return Sys_BtList((BtDevInfo*)frame->arg1, (int)frame->arg2);
case SYS_BTINFO:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<BtAdapterInfo>(frame->arg1)) return -1;
return Sys_BtInfo((BtAdapterInfo*)frame->arg1);
case SYS_SUSPEND:
return Sys_Suspend();
@@ -351,48 +345,53 @@ namespace Montauk {
case SYS_GETTZ:
return Sys_GetTZ();
case SYS_SETUSER:
if (!ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::String(frame->arg2, kMaxUserNameBytes)) return -1;
return Sys_SetUser((int)frame->arg1, (const char*)frame->arg2);
case SYS_GETUSER:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
return Sys_GetUser((char*)frame->arg1, frame->arg2);
case SYS_GETCWD:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
return Sys_GetCwd((char*)frame->arg1, frame->arg2);
case SYS_CHDIR:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
return Sys_Chdir((const char*)frame->arg1);
case SYS_DUPHANDLE:
return Sys_DupHandle((int)frame->arg1);
case SYS_WAIT_HANDLE:
return (int64_t)Sys_WaitHandle((int)frame->arg1, (uint32_t)frame->arg2, frame->arg3);
case SYS_STREAM_CREATE:
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
return Sys_StreamCreate((int*)frame->arg1, (int*)frame->arg2, (uint32_t)frame->arg3);
case SYS_STREAM_READ:
if (!ValidUserPtr(frame->arg2)) return -1;
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
return Sys_StreamRead((int)frame->arg1, (uint8_t*)frame->arg2, (int)frame->arg3);
case SYS_STREAM_WRITE:
if (!ValidUserPtr(frame->arg2)) return -1;
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
return Sys_StreamWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (int)frame->arg3);
case SYS_MAILBOX_CREATE:
if (!ValidUserPtr(frame->arg1) || !ValidUserPtr(frame->arg2)) return -1;
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
return Sys_MailboxCreate((int*)frame->arg1, (int*)frame->arg2);
case SYS_MAILBOX_SEND:
if (frame->arg3 != 0 && !ValidUserPtr(frame->arg3)) return -1;
if (frame->arg4 > 0 && !UserMemory::Range(frame->arg3, frame->arg4, false)) return -1;
return Sys_MailboxSend((int)frame->arg1, (uint32_t)frame->arg2,
(const void*)frame->arg3, (uint16_t)frame->arg4,
(int)frame->arg5);
case SYS_MAILBOX_RECV:
if (frame->arg2 != 0 && !IsUserPtr(frame->arg2)) return -1;
if (frame->arg3 != 0 && !IsUserPtr(frame->arg3)) return -1;
if (!ValidUserPtr(frame->arg4)) return -1;
if (frame->arg5 != 0 && !IsUserPtr(frame->arg5)) return -1;
if (!UserMemory::Writable<uint16_t>(frame->arg4)) return -1;
if (frame->arg2 != 0 && !UserMemory::Writable<uint32_t>(frame->arg2)) return -1;
if (frame->arg3 != 0) {
uint16_t maxCopy = *(uint16_t*)frame->arg4;
if (!UserMemory::Range(frame->arg3, maxCopy, true)) return -1;
}
if (frame->arg5 != 0 && !UserMemory::Writable<int>(frame->arg5)) return -1;
return Sys_MailboxRecv((int)frame->arg1,
IsUserPtr(frame->arg2) ? (uint32_t*)frame->arg2 : nullptr,
IsUserPtr(frame->arg3) ? (void*)frame->arg3 : nullptr,
UserMemory::IsUserPtr(frame->arg2) ? (uint32_t*)frame->arg2 : nullptr,
UserMemory::IsUserPtr(frame->arg3) ? (void*)frame->arg3 : nullptr,
(uint16_t*)frame->arg4,
IsUserPtr(frame->arg5) ? (int*)frame->arg5 : nullptr);
UserMemory::IsUserPtr(frame->arg5) ? (int*)frame->arg5 : nullptr);
case SYS_WAITSET_CREATE:
return Sys_WaitsetCreate();
case SYS_WAITSET_ADD:
@@ -400,9 +399,9 @@ namespace Montauk {
case SYS_WAITSET_REMOVE:
return Sys_WaitsetRemove((int)frame->arg1, (int)frame->arg2);
case SYS_WAITSET_WAIT:
if (frame->arg2 != 0 && !ValidUserPtr(frame->arg2)) return -1;
if (frame->arg2 != 0 && !UserMemory::Writable<IpcWaitResult>(frame->arg2)) return -1;
return Sys_WaitsetWait((int)frame->arg1,
IsUserPtr(frame->arg2) ? (IpcWaitResult*)frame->arg2 : nullptr,
UserMemory::IsUserPtr(frame->arg2) ? (IpcWaitResult*)frame->arg2 : nullptr,
frame->arg3);
case SYS_PROC_OPEN:
return Sys_ProcOpen((int)frame->arg1);
@@ -413,7 +412,7 @@ namespace Montauk {
case SYS_SURFACE_RESIZE:
return Sys_SurfaceResize((int)frame->arg1, frame->arg2);
case SYS_LOAD_LIB:
if (!ValidUserPtr(frame->arg1)) return 0;
if (!UserMemory::String(frame->arg1, 128)) return 0;
return (int64_t)Sys_LoadLib((const char*)frame->arg1);
case SYS_UNLOAD_LIB:
return Sys_UnloadLib(frame->arg1);
@@ -422,21 +421,22 @@ namespace Montauk {
case SYS_GETLIBBASE:
return (int64_t)Sys_GetLibBase(frame->arg1);
case SYS_CRASH_REPORT:
if (!UserMemory::Writable<CrashReportInfo>(frame->arg1)) return -1;
return Sys_CrashReport((CrashReportInfo*)frame->arg1);
case SYS_CLIPBOARD_SET_TEXT:
if (frame->arg2 > 0 && !ValidUserPtr(frame->arg1)) return -1;
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, false)) return -1;
return Sys_ClipboardSetText((const char*)frame->arg1, (uint32_t)frame->arg2);
case SYS_CLIPBOARD_GET_INFO:
if (!ValidUserPtr(frame->arg1)) return -1;
if (!UserMemory::Writable<ClipboardInfo>(frame->arg1)) return -1;
return Sys_ClipboardGetInfo((ClipboardInfo*)frame->arg1);
case SYS_CLIPBOARD_GET_TEXT:
if (frame->arg2 > 0 && !ValidUserPtr(frame->arg1)) return -1;
if (!ValidUserPtr(frame->arg3)) return -1;
if (frame->arg4 != 0 && !IsUserPtr(frame->arg4)) return -1;
return Sys_ClipboardGetText(IsUserPtr(frame->arg1) ? (char*)frame->arg1 : nullptr,
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Writable<uint32_t>(frame->arg3)) return -1;
if (frame->arg4 != 0 && !UserMemory::Writable<uint64_t>(frame->arg4)) return -1;
return Sys_ClipboardGetText(UserMemory::IsUserPtr(frame->arg1) ? (char*)frame->arg1 : nullptr,
(uint32_t)frame->arg2,
(uint32_t*)frame->arg3,
IsUserPtr(frame->arg4) ? (uint64_t*)frame->arg4 : nullptr);
UserMemory::IsUserPtr(frame->arg4) ? (uint64_t*)frame->arg4 : nullptr);
case SYS_CLIPBOARD_CLEAR:
return Sys_ClipboardClear();
default: