diff --git a/src/kernel/drivers/ahci.c b/src/kernel/drivers/ahci.c index 15f637d7..0a3fe6ab 100644 --- a/src/kernel/drivers/ahci.c +++ b/src/kernel/drivers/ahci.c @@ -91,11 +91,16 @@ force_inline bool ahciCmdIssue(ahci *ahciPtr, HBA_PORT *port, int slot) { ahciPtr->cmdSlotsPreping &= ~(1 << slot); // Wait for completion + uint64_t deadline = timerTicks + 5000; while (1) { // In some longer duration reads, it may be helpful to spin on the DPS bit // in the PxIS port field as well (1 << 5) if ((port->ci & (1 << slot)) == 0) break; + if (timerTicks >= deadline) { + debugf("[ahci] Command timeout on slot %d!\n", slot); + return false; + } } return true; diff --git a/src/kernel/filesystems/ext2/ext2_controller.c b/src/kernel/filesystems/ext2/ext2_controller.c index fd34971d..af61a1fd 100644 --- a/src/kernel/filesystems/ext2/ext2_controller.c +++ b/src/kernel/filesystems/ext2/ext2_controller.c @@ -398,8 +398,15 @@ size_t ext2Write(OpenFile *fd, uint8_t *buff, size_t limit) { ext2CachePush(ext2, dir); - // todo! memory leak! spinlockCntWriteAcquire(&dir->globalObject->WLOCK_CACHE); + Ext2CacheObject *cacheBrowse = dir->globalObject->firstCacheObj; + while (cacheBrowse) { + Ext2CacheObject *next = cacheBrowse->next; + VirtualFree(cacheBrowse->buff, + DivRoundUp((cacheBrowse->blocks + 1) * ext2->blockSize, BLOCK_SIZE)); + free(cacheBrowse); + cacheBrowse = next; + } dir->globalObject->firstCacheObj = 0; spinlockCntWriteRelease(&dir->globalObject->WLOCK_CACHE); diff --git a/src/kernel/filesystems/vfs/vfs_controller.c b/src/kernel/filesystems/vfs/vfs_controller.c index 950c084f..a51fbe8c 100644 --- a/src/kernel/filesystems/vfs/vfs_controller.c +++ b/src/kernel/filesystems/vfs/vfs_controller.c @@ -278,11 +278,13 @@ size_t fsUserSeek(void *task, uint32_t fd, int offset, int whence) { } size_t fsReadlink(void *task, char *path, char *buf, int size) { + if (size <= 0) + return ERR(EINVAL); if (strlength(path) == 14 && memcmp(path, "/proc/self/exe", 15) == 0 && currentTask->execname) { // todo: hack-y, needs to be done properly sometime! size_t total = strlength(currentTask->execname); - size_t toCopy = MIN(size, total); + size_t toCopy = MIN((size_t)size, total); memcpy(buf, currentTask->execname, toCopy); return toCopy; // memcpy(buf, "/usr/libexec/webkit2gtk-4.1/MiniBrowser", 40); diff --git a/src/kernel/memory/malloc_glue.c b/src/kernel/memory/malloc_glue.c index 09966a7a..9f25e997 100644 --- a/src/kernel/memory/malloc_glue.c +++ b/src/kernel/memory/malloc_glue.c @@ -5,13 +5,12 @@ #define DEBUG_DLMALLOC_GLUE 0 -void *last = 0; void *sbrk(long increment) { #if DEBUG_DLMALLOC_GLUE debugf("[dlmalloc::sbrk] size{%lx}\n", increment); #endif if (increment < 0) - return 0; // supposed to release, whatever. + return (void *)-1; // supposed to release, whatever. if (!increment) return last; // return 0; diff --git a/src/kernel/memory/paging.c b/src/kernel/memory/paging.c index 36f67b14..a441f6f7 100644 --- a/src/kernel/memory/paging.c +++ b/src/kernel/memory/paging.c @@ -249,7 +249,7 @@ size_t VirtualToPhysicalL(uint64_t *pagedir, size_t virt_addr) { uint32_t pd_index = PDE(virt_addr); uint32_t pt_index = PTE(virt_addr); - // spinlockCntReadAcquire(&WLOCK_PAGING); + spinlockCntReadAcquire(&WLOCK_PAGING); if (!(pagedir[pml4_index] & PF_PRESENT)) goto error; /*else if (pagedir[pml4_index] & PF_PRESENT && @@ -273,13 +273,13 @@ size_t VirtualToPhysicalL(uint64_t *pagedir, size_t virt_addr) { size_t *pt = (size_t *)(PTE_GET_ADDR(pd[pd_index]) + HHDMoffset); if (pt[pt_index] & PF_PRESENT) { - // spinlockCntReadRelease(&WLOCK_PAGING); + spinlockCntReadRelease(&WLOCK_PAGING); return (size_t)(PTE_GET_ADDR(pt[pt_index]) + ((size_t)virt_addr_init & 0xFFF)); } error: - // spinlockCntReadRelease(&WLOCK_PAGING); + spinlockCntReadRelease(&WLOCK_PAGING); return 0; } @@ -348,7 +348,7 @@ void PageDirectoryFree(uint64_t *page_dir) { } void PageDirectoryUserDuplicate(uint64_t *source, uint64_t *target) { - spinlockCntReadAcquire(&WLOCK_PAGING); + spinlockCntWriteAcquire(&WLOCK_PAGING); for (int pml4_index = 0; pml4_index < 512; pml4_index++) { if (!(source[pml4_index] & PF_PRESENT) || source[pml4_index] & PF_PS) continue; @@ -384,13 +384,35 @@ void PageDirectoryUserDuplicate(uint64_t *source, uint64_t *target) { memcpy(ptrTarget, ptrSource, PAGE_SIZE); - spinlockCntReadRelease(&WLOCK_PAGING); - VirtualMapL(target, virt, physTarget, PF_RW | PF_USER); - spinlockCntReadAcquire(&WLOCK_PAGING); + // manually map into target (lock already held as write) + uint64_t tvirt = AMD64_MM_STRIPSX(virt); + uint32_t tpml4 = PML4E(tvirt); + uint32_t tpdp = PDPTE(tvirt); + uint32_t tpd = PDE(tvirt); + uint32_t tpt = PTE(tvirt); + + if (!(target[tpml4] & PF_PRESENT)) { + size_t targ = PagingPhysAllocate(); + target[tpml4] = targ | PF_PRESENT | PF_RW | PF_USER; + } + size_t *tpdpPT = (size_t *)(PTE_GET_ADDR(target[tpml4]) + HHDMoffset); + if (!(tpdpPT[tpdp] & PF_PRESENT)) { + size_t targ = PagingPhysAllocate(); + tpdpPT[tpdp] = targ | PF_PRESENT | PF_RW | PF_USER; + } + size_t *tpdPT = (size_t *)(PTE_GET_ADDR(tpdpPT[tpdp]) + HHDMoffset); + if (!(tpdPT[tpd] & PF_PRESENT)) { + size_t targ = PagingPhysAllocate(); + tpdPT[tpd] = targ | PF_PRESENT | PF_RW | PF_USER; + } + size_t *tptPT = (size_t *)(PTE_GET_ADDR(tpdPT[tpd]) + HHDMoffset); + tptPT[tpt] = (P_PHYS_ADDR(physTarget)) | PF_PRESENT | PF_RW | PF_USER; + + invalidate(virt); } } } } - spinlockCntReadRelease(&WLOCK_PAGING); + spinlockCntWriteRelease(&WLOCK_PAGING); } diff --git a/src/kernel/memory/pmm.c b/src/kernel/memory/pmm.c index 7ea1d78a..153829e2 100644 --- a/src/kernel/memory/pmm.c +++ b/src/kernel/memory/pmm.c @@ -74,9 +74,14 @@ size_t PhysicalAllocate(int pages) { } void PhysicalFree(size_t ptr, int pages) { - // maybe verify no double-frees are occuring.. - spinlockAcquire(&LOCK_PMM); + for (int i = 0; i < pages; i++) { + size_t block = (ptr / BLOCK_SIZE) + i; + if (!BitmapGet(&physical, block)) { + debugf("[pmm] Double-free detected! ptr{%lx} block{%ld}\n", ptr, block); + panic(); + } + } MarkRegion(&physical, (void *)ptr, pages * BLOCK_SIZE, 0); spinlockRelease(&LOCK_PMM); } diff --git a/src/kernel/multitasking/task.c b/src/kernel/multitasking/task.c index a1e14616..ecac1b87 100644 --- a/src/kernel/multitasking/task.c +++ b/src/kernel/multitasking/task.c @@ -239,23 +239,17 @@ void taskKill(uint32_t id, uint16_t ret) { // close any left open files taskInfoFilesDiscard(task->infoFiles, task); - // if (!parentVfork) - // PageDirectoryFree(task->pagedir); + task->state = TASK_STATE_DEAD; + taskInfoPdDiscard(task->infoPd); - // ^ only changes userspace locations so we don't need to change our pagedir // the "reaper" thread will finish everything in a safe context taskCallReaper(task); - task->state = TASK_STATE_DEAD; if (currentTask == task) { - // we're most likely in a syscall context, so... - // taskKillCleanup(task); // left for sched asm volatile("sti"); - // wait until we're outta here - while (1) { - // debugf("GET ME OUT "); - } + while (1) + handControl(); } } diff --git a/src/kernel/multitasking/task_info.c b/src/kernel/multitasking/task_info.c index 1f267079..7725c45b 100644 --- a/src/kernel/multitasking/task_info.c +++ b/src/kernel/multitasking/task_info.c @@ -85,11 +85,8 @@ void taskInfoPdDiscard(TaskInfoPagedir *target) { target->utilizedBy--; if (!target->utilizedBy) { PageDirectoryFree(target->pagedir); - // todo: find a safe way to free target - // cannot be done w/the current layout as it's done inside taskKill and the - // scheduler needs it in case it's switched in between (will point to - // invalid/unsafe memory). maybe with overrides but we'll see later when the - // system is more stable. + spinlockRelease(&target->LOCK_PD); + free(target); } else spinlockRelease(&target->LOCK_PD); } diff --git a/src/kernel/syscalls/io.c b/src/kernel/syscalls/io.c index 4f5288d1..344e4540 100644 --- a/src/kernel/syscalls/io.c +++ b/src/kernel/syscalls/io.c @@ -30,6 +30,7 @@ size_t readHandler(OpenFile *fd, uint8_t *in, size_t limit) { // finalise uint32_t fr = currentTask->tmpRecV; memcpy(in, kernelBuff, fr); + free(kernelBuff); if (currentTask->term.c_lflag & ICANON && fr < limit) in[fr++] = '\n'; // only add newline if we can! diff --git a/src/kernel/syscalls/linux/syscalls_proc.c b/src/kernel/syscalls/linux/syscalls_proc.c index 7984d37c..d9c5b77b 100644 --- a/src/kernel/syscalls/linux/syscalls_proc.c +++ b/src/kernel/syscalls/linux/syscalls_proc.c @@ -169,70 +169,94 @@ void freeArgvIfNeeded(char **argv) { } #define SYSCALL_EXECVE 59 -static size_t syscallExecve(char *filename, char **argv, char **envp) { - // todo: also check for leader & kill the whole thread group for this - assert(currentTask->id == currentTask->tgid); - - assert(argv[0]); // shebang support depends on it atm. check (dep) - dbgSysExtraf("filename{%s}", filename); - spinlockAcquire(¤tTask->infoFs->LOCK_FS); - char *filenameSanitized = fsSanitize(currentTask->infoFs->cwd, filename); - spinlockRelease(¤tTask->infoFs->LOCK_FS); - uint8_t *buff = calloc(256, 1); - - // do a read to check for alternatives, elfExecute() still does its checks - OpenFile *preScan = fsKernelOpen(filenameSanitized, O_RDONLY, 0); - if (!preScan) { - free(filenameSanitized); - return ERR(ENOENT); - } - size_t max = fsRead(preScan, buff, 255); // 1 less so there's always a \0 - fsKernelClose(preScan); - if (RET_IS_ERR(max)) { - free(filenameSanitized); - return max; - } - if (max > 2 && buff[0] == '#' && buff[1] == '!') { - // shebang detected! - char *arg2 = (char *)0; - int spaces = 0; - for (int i = 0; i < max; i++) { - if (buff[i] == ' ') { - if (spaces == 0) { - buff[i] = '\0'; // needs to be null terminated - arg2 = (char *)&buff[i + 1]; +#define SHEBANG_MAX_DEPTH 8 + +static size_t syscallExecve(char *filename, char **argvOriginal, char **envp) { + char **argv = argvOriginal; + int shebangDepth = 0; + char *filenameSanitized = NULL; + + while (1) { + // todo: also check for leader & kill the whole thread group for this + assert(currentTask->id == currentTask->tgid); + + assert(argv[0]); // shebang support depends on it atm. check (dep) + dbgSysExtraf("filename{%s}", filename); + spinlockAcquire(¤tTask->infoFs->LOCK_FS); + filenameSanitized = fsSanitize(currentTask->infoFs->cwd, filename); + spinlockRelease(¤tTask->infoFs->LOCK_FS); + uint8_t *buff = calloc(256, 1); + + OpenFile *preScan = fsKernelOpen(filenameSanitized, O_RDONLY, 0); + if (!preScan) { + free(buff); + free(filenameSanitized); + return ERR(ENOENT); + } + size_t max = fsRead(preScan, buff, 255); + fsKernelClose(preScan); + if (RET_IS_ERR(max)) { + free(buff); + free(filenameSanitized); + return max; + } + + if (max > 2 && buff[0] == '#' && buff[1] == '!') { + if (shebangDepth >= SHEBANG_MAX_DEPTH) { + free(buff); + free(filenameSanitized); + freeItemsIfNeeded(argv); + freeArgvIfNeeded(argv); + return ERR(ELOOP); + } + shebangDepth++; + + char *arg2 = (char *)0; + int spaces = 0; + for (int i = 0; i < max; i++) { + if (buff[i] == ' ') { + if (spaces == 0) { + buff[i] = '\0'; + arg2 = (char *)&buff[i + 1]; + } + spaces++; + } else if (buff[i] == '\n') { + buff[i] = '\0'; + break; } - spaces++; - } else if (buff[i] == '\n') { - buff[i] = '\0'; // for the last arg (if none, 256-255=1 calloc) - break; // no longer needed + don't risk above } + + int argc = 0; + while (argv[argc++]); + int amnt = arg2 ? 2 : 1; + char **injectedArgv = calloc((amnt + argc + 1) * sizeof(char *), 1); + memcpy(&injectedArgv[amnt], argv, argc * sizeof(char *)); + injectedArgv[amnt] = strdup(filename); + + freeArgvIfNeeded(argv); + + char *arg1 = (char *)&buff[2]; + if (arg2 && arg2[0] != '\0') + injectedArgv[1] = strdup(arg2); + injectedArgv[0] = strdup(arg1); + + free(buff); + free(filenameSanitized); + filename = injectedArgv[0]; + argv = injectedArgv; + continue; } - int argc = 0; - while (argv[argc++]) - ; // why not just pass argc. truly beyond me... - int amnt = arg2 ? 2 : 1; - char **injectedArgv = calloc((amnt + argc + 1) * sizeof(char *), 1); - memcpy(&injectedArgv[amnt], argv, argc * sizeof(char *)); - injectedArgv[amnt] = strdup(filename); // replace [0] w/original (dep) - - freeArgvIfNeeded(argv); // ! don't use argv anymore - - char *arg1 = (char *)&buff[2]; - if (arg2 && arg2[0] != '\0') - injectedArgv[1] = strdup(arg2); - injectedArgv[0] = strdup(arg1); - - free(buff); // ! don't use anything defined before after this - syscallExecve(injectedArgv[0], injectedArgv, envp); - assert(false); // won't return, injectedArgv & buff are above HHDM - } else if (max > 4 && buff[EI_MAG0] == ELFMAG0 && buff[EI_MAG1] == ELFMAG1 && - buff[EI_MAG2] == ELFMAG2 && buff[EI_MAG3] == ELFMAG3) { - // standard elf executable, go on - } else { - // both unnecessary, won't do anything w/them :^) - freeItemsIfNeeded(argv); // depends on the argv so NEEDS to be first + + if (max > 4 && buff[EI_MAG0] == ELFMAG0 && buff[EI_MAG1] == ELFMAG1 && + buff[EI_MAG2] == ELFMAG2 && buff[EI_MAG3] == ELFMAG3) { + free(buff); + break; + } + + free(buff); + free(filenameSanitized); + freeItemsIfNeeded(argv); freeArgvIfNeeded(argv); return ERR(ENOEXEC); } @@ -247,8 +271,8 @@ static size_t syscallExecve(char *filename, char **argv, char **envp) { free(arguments.valPlace); free(environment.ptrPlace); free(environment.valPlace); - freeItemsIfNeeded(argv); // depends on the argv so NEEDS to be first - freeArgvIfNeeded(argv); // ! don't use ANY argv after this + freeItemsIfNeeded(argv); + freeArgvIfNeeded(argv); if (!ret) return ERR(ENOENT); diff --git a/src/kernel/syscalls/signals.c b/src/kernel/syscalls/signals.c index 5f75b027..0e376682 100644 --- a/src/kernel/syscalls/signals.c +++ b/src/kernel/syscalls/signals.c @@ -164,7 +164,7 @@ int signalsPendingDecide(Task *task) { // find a single valid pending signal uint64_t pendingList = atomicBitmapGet(&task->sigPendingList); for (int i = 0; i < _NSIG; i++) { - if (pendingList & (1 << i) && !(task->sigBlockList & (1 << i))) + if (pendingList & ((sigset_t)1 << i) && !(task->sigBlockList & ((sigset_t)1 << i))) return i; } return -1; @@ -217,7 +217,7 @@ void signalsPendingHandleSys(void *taskPtr, uint64_t *rsp, // (also SA_NODEFER) sigset_t oldMask = task->sigBlockList; - task->sigBlockList |= (1 << signal) | atomicRead64(&action->sa_mask); + task->sigBlockList |= ((sigset_t)1 << signal) | atomicRead64(&action->sa_mask); atomicBitmapClear(&task->sigPendingList, signal); // now that it is blocked // establish a "safe" struct, that we could theoretically safely iretq to @@ -319,7 +319,7 @@ void signalsPendingHandleSched(void *taskPtr) { // (also SA_NODEFER) sigset_t oldMask = task->sigBlockList; - task->sigBlockList |= (1 << signal) | atomicRead64(&action->sa_mask); + task->sigBlockList |= ((sigset_t)1 << signal) | atomicRead64(&action->sa_mask); atomicBitmapClear(&task->sigPendingList, signal); // now that it is blocked AsmPassedInterrupt oldstate = {0}; @@ -441,7 +441,7 @@ size_t signalsSigreturnSyscall(void *taskPtr) { task->syscallRegs = 0; task->syscallRsp = 0; - task->sigBlockList = ucontext->oldmask & ~((1 << SIGKILL) | (1 << SIGSTOP)); + task->sigBlockList = ucontext->oldmask & ~(((sigset_t)1 << SIGKILL) | ((sigset_t)1 << SIGSTOP)); asm_finalize((size_t)iretqRsp, VirtualToPhysical((size_t)task->infoPd->pagedir));