#include "api/syscall.h" #include "hal/memory.h" #include "jove.h" #include "lib/printf.h" #include "syscall.h" static int s_get_untyped( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pml4, size_t payload_bytes, void *payload_data, jove_perm_obj_t *untyped_ret) { size_t bytes_needed = sizeof(struct syscall_pagedir_map); CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for payload."); struct syscall_pagedir_map *payload = payload_data; if(payload->virtual_address > 0xFFFF800000000000ULL) { kprintf("%s: Virtual address is above user limit.\n", __func__); return EBADARG; } bytes_needed += payload->untyped_pathlen << 1; CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for untyped path."); errno = 0; jove_perm_obj_t untyped = link_try_traverse_objdir( objdir, lockstack, payload->untyped_pathlen, payload->untyped_path); if(errno) { kprintf("%s: Untyped obj failed for the reason: %s\n", __func__, errstr(errno)); return errno; } CHECK_OBJTYPE(untyped.obj, JOVE_OBJ_UNTYPED, "Untyped path does not point to an untyped object."); CHECK_OBJPERM(untyped, JOVE_PERM_MUTATE, "Untyped object does not have MUTATE permission."); jove_untyped_t *untyped_data = obj_deref(untyped.obj); if((uintptr_t)untyped_data & 0xFFF) { kprintf("%s: Untyped object is not page aligned.\n", __func__); return EALIGN; } if(untyped_data->limit != 0x1000) { kprintf("%s: Untyped object is not page sized. (expected 0x1000 got 0x%X)\n", __func__, untyped_data->limit); return EBADSIZE; } *untyped_ret = untyped; return 0; } static int s_syscall_pagedir_unmap( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data, jove_perm_obj_t *none_ret) { size_t bytes_needed = sizeof(struct syscall_pagedir_unmap); CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for payload"); struct syscall_pagedir_unmap *payload = payload_data; if(payload->virtual_address > 0xFFFF800000000000ULL) { kprintf("%s: Virtual address is above user limit.\n", __func__); return EBADARG; } bytes_needed += payload->none_pathlen * 2; CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for none path"); jove_perm_obj_t none = link_try_traverse_objdir( objdir, lockstack, payload->none_pathlen, payload->none_path); if(errno) { kprintf("%s: None obj retrieval failed for the reason: %s\n", __func__, errstr(errno)); return errno; } CHECK_OBJTYPE(none.obj, JOVE_OBJ_NONE, "None path does not point to none object."); *none_ret = none; return 0; } static int s_syscall_pagedir_map_frame( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data) { jove_perm_obj_t untyped = { .obj = NULL, .permissions = 0 }; int sysret = s_get_untyped(lockstack, objdir, pagedir, payload_bytes, payload_data, &untyped); if(sysret != 0) { return sysret; } struct syscall_pagedir_map *payload = payload_data; sysret = pagedir_map_untyped_frame(pagedir, &untyped, payload->virtual_address, payload->page_flags); if(sysret == 0) obj_settype(untyped.obj, JOVE_OBJ_NONE); return sysret; } static int s_syscall_pagedir_map_table( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data) { jove_perm_obj_t untyped = { .obj = NULL, .permissions = 0 }; int sysret = s_get_untyped(lockstack, objdir, pagedir, payload_bytes, payload_data, &untyped); if(sysret != 0) { return sysret; } struct syscall_pagedir_map *payload = payload_data; sysret = pagedir_map_untyped_table(pagedir, &untyped, payload->virtual_address); if(sysret == 0) obj_settype(untyped.obj, JOVE_OBJ_NONE); return sysret; } static int s_syscall_pagedir_map_shmem( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data) { size_t bytes_needed = sizeof(struct syscall_pagedir_map_shmem); CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for payload."); struct syscall_pagedir_map_shmem *payload = payload_data; if(payload->virtual_address > 0xFFFF800000000000ULL) { kprintf("%s: Virtual address is above user limit.\n", __func__); return EBADARG; } bytes_needed += payload->shmem_pathlen << 1; CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for shared memory path."); errno = 0; jove_perm_obj_t shmem = link_try_traverse_objdir( objdir, lockstack, payload->shmem_pathlen, payload->shmem_path); if(errno) { klogf("Unable to retrieve shared memory object %P : %s\n", payload->shmem_path, payload->shmem_pathlen, errstr(errno)); return errno; } CHECK_OBJTYPE(shmem.obj, JOVE_OBJ_SHMEMORY, "Shared memory path does not point to a shared memory object."); uintmax_t shmem_value = obj_getvalue(shmem.obj); uint8_t shmem_pages = shmem_value & 0xFFF; if(payload->page_offset >= shmem_pages) { klogf("Page offset goes beyond size of shared memory object: (%i >= %i)\n", payload->page_offset, shmem_pages); return -EOOB; } return pagedir_map_shmem_frame(pagedir, &shmem, payload->page_offset, payload->virtual_address, payload->page_flags); } static int s_syscall_pagedir_unmap_frame( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data) { jove_perm_obj_t none; int sysret = s_syscall_pagedir_unmap(lockstack, objdir, pagedir, payload_bytes, payload_data, &none); if(!sysret) return sysret; struct syscall_pagedir_unmap *payload = payload_data; return pagedir_unmap_untyped_frame(pagedir, none.obj, payload->virtual_address); } static int s_syscall_pagedir_unmap_table( lockstack_t *lockstack, jove_owned_obj_t *objdir, jove_owned_obj_t *pagedir, size_t payload_bytes, void *payload_data) { jove_perm_obj_t none; int sysret = s_syscall_pagedir_unmap(lockstack, objdir, pagedir, payload_bytes, payload_data, &none); if(!sysret) return sysret; struct syscall_pagedir_unmap *payload = payload_data; return pagedir_unmap_untyped_table(pagedir, none.obj, payload->virtual_address); } int _syscall_handle_pagedir(syscall_context_t *ctx) { lockstack_t *lockstack = &ctx->lockstack; struct syscall_header *header = ctx->header; jove_owned_obj_t *objdir = ctx->objdir; jove_perm_obj_t *target = &ctx->target; size_t bytes_left = ctx->bytes_left; void *payload = ctx->payload; switch(header->callid) { case SYSCALL_PAGEDIR_MAP_FRAME: if(target->permissions & SYSCALL_PERM_PAGEDIR_MAP_FRAME) return s_syscall_pagedir_map_frame(lockstack, objdir, target->obj, bytes_left, payload); return -EPERM; case SYSCALL_PAGEDIR_MAP_TABLE: if(target->permissions & SYSCALL_PERM_PAGEDIR_MAP_TABLE) return s_syscall_pagedir_map_table(lockstack, objdir, target->obj, bytes_left, payload); return -EPERM; case SYSCALL_PAGEDIR_MAP_SHMEM: if(target->permissions & SYSCALL_PERM_PAGEDIR_MAP_SHMEM) return s_syscall_pagedir_map_shmem(lockstack, objdir, target->obj, bytes_left, payload); return -EPERM; case SYSCALL_PAGEDIR_UNMAP_FRAME: if(target->permissions & SYSCALL_PERM_PAGEDIR_UNMAP_FRAME) return s_syscall_pagedir_unmap_frame(lockstack, objdir, target->obj, bytes_left, payload); return -EPERM; case SYSCALL_PAGEDIR_UNMAP_TABLE: if(target->permissions & SYSCALL_PERM_PAGEDIR_UNMAP_TABLE) return s_syscall_pagedir_unmap_table(lockstack, objdir, target->obj, bytes_left, payload); return -EPERM; default: kprintf("syscall_handle_pagedir: Pagedir does not support syscall %i\n", header->callid); return EBADARG; } }