diff --git a/.github/workflows/it-compiles-test.yml b/.github/workflows/it-compiles-test.yml index 35b0c9c..1f661f7 100644 --- a/.github/workflows/it-compiles-test.yml +++ b/.github/workflows/it-compiles-test.yml @@ -1,13 +1,16 @@ name: It Compiles! -on: [push] +on: [push, workflow_dispatch] jobs: Compile: runs-on: ubuntu-latest - container: archlinux:latest + #container: archlinux:latest + container: ubuntu:latest steps: - name: Install dependencies + #run: > + # pacman -Sy --noconfirm --needed glibc clang nasm lld cmake ninja xorriso git run: > - pacman -Sy --noconfirm --needed glibc clang nasm lld cmake ninja xorriso git + apt-get update && apt-get install clang lld cmake ninja-build xorriso -y - name: Checkout repository uses: actions/checkout@v3 - name: Configure source diff --git a/CMakeLists.txt b/CMakeLists.txt index f4c467b..5f78141 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,6 @@ set(FILES ${PROJECT_SOURCE_DIR}/limine.cfg crescent user_tty - initramfs.tar ) add_executable(crescent src/main.c) @@ -26,7 +25,7 @@ target_compile_options(crescent PRIVATE -mgeneral-regs-only -mno-red-zone -mcmodel=kernel -fno-stack-protector -fno-exceptions -fno-rtti -fno-omit-frame-pointer - -fPIC -nostdlibinc -fno-builtin>) + -fPIC -nostdlibinc -Werror=switch -Werror=noderef>) target_compile_options(crescent PRIVATE $<$: -Wno-unused-command-line-argument>) target_link_options(crescent PRIVATE -T ${PROJECT_SOURCE_DIR}/.config/kernel.ld) diff --git a/include/crescent/handle.h b/include/crescent/handle.h new file mode 100644 index 0000000..c525224 --- /dev/null +++ b/include/crescent/handle.h @@ -0,0 +1,10 @@ +#ifndef CRESCENT_HANDLE_H +#define CRESCENT_HANDLE_H + +#include + +#define INVALID_HANDLE ((Handle) -1) + +typedef uint64_t Handle; + +#endif \ No newline at end of file diff --git a/include/crescent/sys.h b/include/crescent/sys.h index 87db53b..8e4e439 100644 --- a/include/crescent/sys.h +++ b/include/crescent/sys.h @@ -1,10 +1,6 @@ #ifndef CRESCENT_SYS_H #define CRESCENT_SYS_H -#include - -#define INVALID_HANDLE ((Handle) -1) - -typedef uint64_t Handle; +#include "handle.h" typedef enum { SHUTDOWN_TYPE_REBOOT diff --git a/limine.cfg b/limine.cfg index a48ee2e..9ec5cf8 100644 --- a/limine.cfg +++ b/limine.cfg @@ -11,7 +11,4 @@ MODULE_CMDLINE=Tamsyn8x16r.psf MODULE_PATH=boot:///user_tty MODULE_CMDLINE=user_tty -MODULE_PATH=boot:///initramfs.tar -MODULE_CMDLINE=initramfs.tar - KASLR=no diff --git a/src/arch/misc.h b/src/arch/misc.h index 76e7e50..14c7c0c 100644 --- a/src/arch/misc.h +++ b/src/arch/misc.h @@ -1,6 +1,12 @@ #pragma once +#include "types.h" void arch_hlt(); void arch_spinloop_hint(); -void arch_reboot(); \ No newline at end of file +void arch_reboot(); + +#define __user __attribute__((address_space(1), noderef)) + +bool arch_mem_copy_to_user(__user void* restrict user, const void* restrict kernel, usize size); +bool arch_mem_copy_to_kernel(void* restrict kernel, __user const void* restrict user, usize size); diff --git a/src/arch/x86/CMakeLists.txt b/src/arch/x86/CMakeLists.txt index bb11c05..0a6f0f3 100644 --- a/src/arch/x86/CMakeLists.txt +++ b/src/arch/x86/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(crescent PRIVATE mod.c mem/map.c mem/mem.c + mem/misc.S interrupts/interrupts.c interrupts/idt.c interrupts/int_stubs.S diff --git a/src/arch/x86/interrupts/exceptions.c b/src/arch/x86/interrupts/exceptions.c index 214d968..0422a08 100644 --- a/src/arch/x86/interrupts/exceptions.c +++ b/src/arch/x86/interrupts/exceptions.c @@ -61,6 +61,14 @@ GENERIC_EX(security, "security exception") IrqStatus ex_pf(void* void_ctx, void*) { InterruptCtx* ctx = (InterruptCtx*) void_ctx; + Task* self = arch_get_cur_task(); + if (self->handler_ip) { + ctx->ip = (usize) self->handler_ip; + ctx->sp = (usize) self->handler_sp; + self->handler_ip = 0; + return IRQ_ACK; + } + bool present = ctx->error & 1; bool write = ctx->error & 1 << 1; bool user = ctx->error & 1 << 2; @@ -92,21 +100,11 @@ IrqStatus ex_pf(void* void_ctx, void*) { backtrace_display(false); spinlock_unlock(&PRINT_LOCK); - Task* self = arch_get_cur_task(); if (ctx->cs == 0x2b) { kprintf("killing user task '%s'\n", self->name); __asm__ volatile("sti"); sched_kill_cur(); } - else if (self->inside_syscall) { - ctx->sp = ctx->rbp + 8; - ctx->rbp = *(const u64*) ctx->rbp; - ctx->ip = *(const u64*) ctx->sp; - ctx->sp += 8; - ctx->rax = ERR_FAULT; - kprintf("%" PRIfg, COLOR_RESET); - return IRQ_ACK; - } lapic_ipi_all(LAPIC_MSG_PANIC); diff --git a/src/arch/x86/mem/misc.S b/src/arch/x86/mem/misc.S new file mode 100644 index 0000000..fcaee8a --- /dev/null +++ b/src/arch/x86/mem/misc.S @@ -0,0 +1,45 @@ +// bool arch_mem_copy_to_user(__user void* restrict user, const void* restrict kernel, usize size); +// bool arch_mem_copy_to_kernel(void* restrict kernel, __user const void* restrict user, usize size); + +#include + +.globl arch_mem_copy_to_user +.globl arch_mem_copy_to_kernel + +.type arch_mem_copy_to_user, @function +arch_mem_copy_to_user: + push %rbp + mov %rsp, %rbp + + lea 1f(%rip), %rax + mov %rax, %gs:X86TASK_HANDLER_IP_OFF + mov %rsp, %gs:X86TASK_HANDLER_SP_OFF + + call memcpy + + pop %rbp + mov $1, %eax + ret +1: + pop %rbp + xor %eax, %eax + ret + +.type arch_mem_copy_to_kernel, @function +arch_mem_copy_to_kernel: + push %rbp + mov %rsp, %rbp + + lea 1f(%rip), %rax + mov %rax, %gs:X86TASK_HANDLER_IP_OFF + mov %rsp, %gs:X86TASK_HANDLER_SP_OFF + + call memcpy + + pop %rbp + mov $1, %eax + ret +1: + pop %rbp + xor %eax, %eax + ret \ No newline at end of file diff --git a/src/arch/x86/sched/usermode.inc b/src/arch/x86/sched/usermode.inc index 1f1ee40..d93e413 100644 --- a/src/arch/x86/sched/usermode.inc +++ b/src/arch/x86/sched/usermode.inc @@ -1,6 +1,7 @@ #ifndef USERMODE_INC #define USERMODE_INC -#define X86TASK_INSIDE_SYSCALL_OFFSET 380 +#define X86TASK_HANDLER_IP_OFF 368 +#define X86TASK_HANDLER_SP_OFF 376 #endif \ No newline at end of file diff --git a/src/arch/x86/sched/x86_task.h b/src/arch/x86/sched/x86_task.h index bf41c1c..4455fcc 100644 --- a/src/arch/x86/sched/x86_task.h +++ b/src/arch/x86/sched/x86_task.h @@ -18,10 +18,16 @@ typedef struct X86Task { bool user; } X86Task; +#define X86TASK_COMMON_OFF 72 +#define TASK_HANDLER_IP_OFF 296 +#define TASK_HANDLER_SP_OFF 304 + #include "usermode.inc" -static_assert(offsetof(X86Task, common) + offsetof(Task, inside_syscall) == X86TASK_INSIDE_SYSCALL_OFFSET); -static_assert(offsetof(Task, inside_syscall) == 308); -static_assert(offsetof(X86Task, common) == 72); +static_assert(offsetof(X86Task, common) == X86TASK_COMMON_OFF); +static_assert(offsetof(Task, handler_ip) == TASK_HANDLER_IP_OFF); +static_assert(offsetof(Task, handler_sp) == TASK_HANDLER_SP_OFF); +static_assert(X86TASK_COMMON_OFF + TASK_HANDLER_IP_OFF == X86TASK_HANDLER_IP_OFF); +static_assert(X86TASK_COMMON_OFF + TASK_HANDLER_SP_OFF == X86TASK_HANDLER_SP_OFF); void x86_task_add_map_page(X86Task* task, struct Page* page); void x86_task_remove_map_page(X86Task* task, struct Page* page); \ No newline at end of file diff --git a/src/mem/user.h b/src/mem/user.h new file mode 100644 index 0000000..17bb07f --- /dev/null +++ b/src/mem/user.h @@ -0,0 +1,10 @@ +#pragma once +#include "arch/misc.h" + +static inline bool mem_copy_to_user(__user void* restrict user, const void* restrict kernel, usize size) { + return arch_mem_copy_to_user(user, kernel, size); +} + +static inline bool mem_copy_to_kernel(void* restrict kernel, __user const void* restrict user, usize size) { + return arch_mem_copy_to_kernel(kernel, user, size); +} diff --git a/src/mem/vm.c b/src/mem/vm.c index 690024f..f9b0512 100644 --- a/src/mem/vm.c +++ b/src/mem/vm.c @@ -106,7 +106,7 @@ void* vm_user_alloc_backed(Process* process, usize count, PageFlags flags, void* } mutex_lock(&process->mapping_lock); - if (!process_add_mapping(process, (usize) vm, count * PAGE_SIZE)) { + if (!process_add_mapping(process, (usize) vm, count * PAGE_SIZE, flags & PF_WRITE)) { mutex_unlock(&process->mapping_lock); vm_user_dealloc(process, vm, count); if (kernel_vm) { @@ -192,7 +192,3 @@ bool vm_user_dealloc_backed(Process* process, void* ptr, usize count, void* kern } return true; } - -bool vm_user_verify(Process* process, void* ptr, size_t len) { - return process_is_mapped(process, (usize) ptr, len); -} diff --git a/src/mem/vm.h b/src/mem/vm.h index 62a8f4d..3befcf0 100644 --- a/src/mem/vm.h +++ b/src/mem/vm.h @@ -19,5 +19,3 @@ void vm_user_dealloc(Process* process, void* ptr, usize count); void* vm_user_alloc_backed(Process* process, usize count, PageFlags flags, void** kernel_mapping); void vm_user_dealloc_kernel(void* kernel_mapping, usize count); bool vm_user_dealloc_backed(Process* process, void* ptr, usize count, void* kernel_mapping); - -bool vm_user_verify(Process* process, void* ptr, size_t len); diff --git a/src/sched/process.c b/src/sched/process.c index d0383ba..98c0e27 100644 --- a/src/sched/process.c +++ b/src/sched/process.c @@ -22,35 +22,36 @@ Mapping* process_find_mapping(Process* self, usize addr) { return NULL; } -bool process_is_mapped(Process* self, usize start, usize size) { - usize end = start + size; +bool process_is_mapped(Process* self, const void* start, usize size, bool rw) { + usize end = (usize) start + size; const Mapping* mapping = (const Mapping*) self->mappings.hook.root; while (mapping) { usize mapping_start = mapping->base; usize mapping_end = mapping_start + mapping->size; - if (start < mapping_end && mapping_start < end) { - return true; + if ((usize) start < mapping_end && mapping_start < end) { + return !rw || mapping->rw; } - if (start < mapping->base) { + if ((usize) start < mapping->base) { mapping = (const Mapping*) mapping->hook.left; } - else if (start > mapping->base) { + else if ((usize) start > mapping->base) { mapping = (const Mapping*) mapping->hook.right; } } return false; } -bool process_add_mapping(Process* self, usize base, usize size) { +bool process_add_mapping(Process* self, usize base, usize size, bool rw) { Mapping* mapping = kcalloc(sizeof(Mapping)); if (!mapping) { return false; } mapping->base = base; mapping->size = size; + mapping->rw = rw; Mapping* m = (Mapping*) self->mappings.hook.root; if (!m) { diff --git a/src/sched/process.h b/src/sched/process.h index 0dc57ab..3972d63 100644 --- a/src/sched/process.h +++ b/src/sched/process.h @@ -7,6 +7,7 @@ typedef struct { RbTreeNode hook; usize base; usize size; + bool rw; } Mapping; typedef struct { @@ -30,8 +31,8 @@ typedef struct Process { Process* process_new(); Process* process_new_user(); -bool process_add_mapping(Process* self, usize base, usize size); +bool process_add_mapping(Process* self, usize base, usize size, bool rw); bool process_remove_mapping(Process* self, usize base); -bool process_is_mapped(Process* self, usize start, usize size); +bool process_is_mapped(Process* self, const void* start, usize size, bool rw); void process_add_thread(Process* self, Task* task); void process_remove_thread(Process* self, Task* task); diff --git a/src/sched/task.h b/src/sched/task.h index 52bfbfe..4995222 100644 --- a/src/sched/task.h +++ b/src/sched/task.h @@ -40,13 +40,14 @@ typedef struct Task { struct Task* signal_waiters; Mutex signal_waiters_lock; EventQueue event_queue; + void* handler_ip; + void* handler_sp; TaskStatus status; u32 caps; u8 level; u8 priority; bool pin_level; bool pin_cpu; - bool inside_syscall; atomic_bool killed; } Task; diff --git a/src/sys/syscalls.c b/src/sys/syscalls.c index 72211f4..620526a 100644 --- a/src/sys/syscalls.c +++ b/src/sys/syscalls.c @@ -11,22 +11,23 @@ #include "mem/page.h" #include "crescent/fb.h" #include "dev/fb.h" -#include "utils.h" +#include "crescent/sys.h" +#include "mem/user.h" void sys_exit(int status); Handle sys_create_thread(void (*fn)(void*), void* arg); int sys_kill_thread(Handle handle); -int sys_dprint(const char* msg, size_t len); +int sys_dprint(__user const char* msg, size_t len); void sys_sleep(usize ms); int sys_wait_thread(Handle handle); -int sys_wait_for_event(Event* res); -int sys_poll_event(Event* res); +int sys_wait_for_event(__user Event* res); +int sys_poll_event(__user Event* res); int sys_shutdown(ShutdownType type); bool sys_request_cap(u32 cap); void* sys_mmap(size_t size, int protection); -int sys_munmap(void* ptr, size_t size); +int sys_munmap(__user void* ptr, size_t size); int sys_close(Handle handle); -int sys_enumerate_framebuffers(SysFramebuffer* res, size_t* count); +int sys_enumerate_framebuffers(__user SysFramebuffer* res, __user size_t* count); __attribute__((used)) void* syscall_handlers[] = { sys_create_thread, @@ -46,7 +47,6 @@ __attribute__((used)) void* syscall_handlers[] = { sys_munmap, sys_close, - sys_enumerate_framebuffers }; @@ -57,8 +57,6 @@ static const char* CAP_STRS[CAP_MAX] = { [CAP_MANAGE_POWER] = "MANAGE_POWER" }; -#define VALIDATE_PTR(ptr) if ((usize) (ptr) >= HHDM_OFFSET) return ERR_INVALID_ARG - bool sys_request_cap(u32 cap) { if (cap >= CAP_MAX) { return false; @@ -111,25 +109,30 @@ int sys_shutdown(ShutdownType type) { return ERR_INVALID_ARG; } -int sys_wait_for_event(Event* res) { - VALIDATE_PTR(res); - +int sys_wait_for_event(__user Event* res) { Task* self = arch_get_cur_task(); - start_catch_faults(); - if (!event_queue_get(&self->event_queue, res)) { + + Event kernel_res; + + if (!event_queue_get(&self->event_queue, &kernel_res)) { sched_block(TASK_STATUS_WAITING); - event_queue_get(&self->event_queue, res); + event_queue_get(&self->event_queue, &kernel_res); } - end_catch_faults(); + + if (!mem_copy_to_user(res, &kernel_res, sizeof(Event))) { + return ERR_FAULT; + } + return 0; } -int sys_poll_event(Event* res) { - VALIDATE_PTR(res); +int sys_poll_event(__user Event* res) { Task* self = arch_get_cur_task(); - start_catch_faults(); - bool result = event_queue_get(&self->event_queue, res); - end_catch_faults(); + Event kernel_res; + bool result = event_queue_get(&self->event_queue, &kernel_res); + if (!mem_copy_to_user(res, &kernel_res, sizeof(Event))) { + return ERR_FAULT; + } return !result; } @@ -191,11 +194,18 @@ void sys_sleep(usize ms) { sched_sleep(ms * US_IN_MS); } -int sys_dprint(const char* msg, size_t len) { - VALIDATE_PTR(msg); - start_catch_faults(); - kputs(msg, len); - end_catch_faults(); +int sys_dprint(__user const char* msg, size_t len) { + char* buffer = kmalloc(len); + if (!buffer) { + return ERR_NO_MEM; + } + if (!mem_copy_to_kernel(buffer, msg, len)) { + kfree(buffer, len); + return ERR_FAULT; + } + + kputs(buffer, len); + kfree(buffer, len); return 0; } @@ -277,14 +287,18 @@ void* sys_mmap(size_t size, int protection) { return res; } -int sys_munmap(void* ptr, size_t size) { - VALIDATE_PTR(ptr); +int sys_munmap(__user void* ptr, size_t size) { + if (!size || (size & (PAGE_SIZE - 1))) { + return ERR_INVALID_ARG; + } - if (!ptr || !size || (size & (PAGE_SIZE - 1))) { + // todo use process mappings instead of size + Task* self = arch_get_cur_task(); + if (!process_is_mapped(self->process, (const void*) ptr, size, false)) { return ERR_INVALID_ARG; } - if (!vm_user_dealloc_backed(arch_get_cur_task()->process, ptr, size / PAGE_SIZE, NULL)) { + if (!vm_user_dealloc_backed(self->process, (void*) ptr, size / PAGE_SIZE, NULL)) { return ERR_INVALID_ARG; } arch_invalidate_mapping(arch_get_cur_task()->process); @@ -313,19 +327,19 @@ int sys_close(Handle handle) { return 0; } -int sys_enumerate_framebuffers(SysFramebuffer* res, size_t* count) { +int sys_enumerate_framebuffers(__user SysFramebuffer* res, __user size_t* count) { Task* self = arch_get_cur_task(); if (!(self->caps & CAP_DIRECT_FB_ACCESS)) { return ERR_NO_PERMISSIONS; } - VALIDATE_PTR(res); - VALIDATE_PTR(count); - // todo support more than one if (primary_fb) { if (count) { - *count = 1; + size_t kernel_count = 1; + if (!mem_copy_to_user(count, &kernel_count, sizeof(size_t))) { + return ERR_FAULT; + } } if (count && res) { usize size = primary_fb->height * primary_fb->pitch; @@ -339,12 +353,12 @@ int sys_enumerate_framebuffers(SysFramebuffer* res, size_t* count) { } } - SysFramebuffer safe_res = *primary_fb; - safe_res.base = mem; + SysFramebuffer kernel_res = *primary_fb; + kernel_res.base = mem; - start_catch_faults(); - memcpy(res, &safe_res, sizeof(SysFramebuffer)); - end_catch_faults(); + if (!mem_copy_to_user(res, &kernel_res, sizeof(SysFramebuffer))) { + return ERR_FAULT; + } } } else { diff --git a/src/sys/utils.h b/src/sys/utils.h deleted file mode 100644 index 3b97160..0000000 --- a/src/sys/utils.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "arch/cpu.h" - -static inline void start_catch_faults() { - arch_get_cur_task()->inside_syscall = true; -} - -static inline void end_catch_faults() { - arch_get_cur_task()->inside_syscall = false; -} \ No newline at end of file diff --git a/src/utils/handle.h b/src/utils/handle.h index f8f15c5..2757256 100644 --- a/src/utils/handle.h +++ b/src/utils/handle.h @@ -1,6 +1,6 @@ #pragma once #include "types.h" -#include "crescent/sys.h" +#include "crescent/handle.h" #include "sched/mutex.h" typedef enum { @@ -22,8 +22,6 @@ typedef struct { Mutex lock; } HandleTable; -#define INVALID_HANDLE ((Handle) -1) - Handle handle_tab_insert(HandleTable* self, void* data, HandleType type); HandleEntry* handle_tab_get(HandleTable* self, Handle handle); bool handle_tab_close(HandleTable* self, Handle handle);