#include "arch/x86_64/hal/obj.h" #include "proc/process.h" #include "jove.h" #include "lib/printf.h" #include "sys/objdir.h" #include "syscall.h" int s_syscall_objdir_objtype( jove_owned_obj_t *objdir, jove_owned_obj_t *target_dir, size_t payload_size, void *payload_data) { size_t bytes_needed = 2; CHECK_TOOSMALL(bytes_needed, payload_size, "Message is too small for payload."); uint16_t local_idx = *((uint16_t*)payload_data); if(local_idx > OBJDIR_ENTRIES) { kprintf("%s: Object index is out of bounds (>= 512)\n", __func__); return EOOB; } jove_obj_t local_obj = objdir_peeklocal(target_dir, local_idx); return obj_peektype(local_obj); } static int s_syscall_objdir_swap(jove_owned_obj_t *target_obj, lockstack_t *lockstack, jove_owned_obj_t *rootdir, size_t bytes_left, void *payload_data) { size_t bytes_needed = sizeof(struct syscall_objdir_swap); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload."); struct syscall_objdir_swap *payload = payload_data; bytes_needed += payload->other_path_length * sizeof(objpath_part_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other path."); jove_owned_obj_t *obj_a = lockstack_push(lockstack, objdir_trygetlocal(target_obj, payload->index)); if(obj_a == NULL) { klogf("Getting local object %i failed : %s\n", payload->index, errstr(errno)); return -errno; } jove_perm_obj_t objdir_b = link_try_traverse_objdir(rootdir, lockstack, payload->other_path_length - 1, payload->other_path); if(objdir_b.obj == NULL) { klogf("Getting object %P failed : %s\n", payload->other_path, payload->other_path_length, errstr(errno)); return -errno; } CHECK_OBJPERM(objdir_b, SYSCALL_PERM_OBJDIR_SWAP_TGT, "Other object is missing permission"); jove_owned_obj_t *obj_b = lockstack_push(lockstack, objdir_trygetlocal(objdir_b.obj, payload->other_path[payload->other_path_length-1])); if(obj_b == NULL) { klogf("Getting object %P failed : %s\n", payload->other_path, payload->other_path_length, errstr(errno)); return -errno; } objdir_swapobj(obj_a, obj_b); return 0; } static int s_syscall_objdir_link(jove_owned_obj_t *target_obj, lockstack_t *lockstack, jove_owned_obj_t *rootdir_obj, size_t bytes_left, void *payload_data) { size_t bytes_needed = sizeof(struct syscall_objdir_link); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); struct syscall_objdir_link *payload = payload_data; bytes_needed += payload->other_path_length * sizeof(objpath_part_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other object"); jove_owned_obj_t *link_obj = lockstack_push(lockstack, objdir_trygetlocal(target_obj, payload->index)); if(link_obj == NULL) { klogf("Getting local object %i failed : %s\n", payload->index, errstr(errno)); return -errno; } CHECK_OBJTYPE(link_obj, JOVE_OBJ_LINK, "Local object is not a link object"); jove_perm_obj_t dest_obj = link_try_traverse_objdir(rootdir_obj, lockstack, payload->other_path_length, payload->other_path); if(dest_obj.obj == NULL) { klogf("Getting destination object %P failed : %s\n", payload->other_path, payload->other_path_length, errstr(errno)); return -errno; } if(obj_gettype(dest_obj.obj) != JOVE_OBJ_NONE) { klogf("Destination object %P is not empty\n", payload->other_path, payload->other_path_length); return -EFULL; } CHECK_OBJPERM(dest_obj, SYSCALL_PERM_OBJDIR_LINK_TGT, "Destination object is missing permissions"); return link_dup(link_obj, dest_obj.obj); } int _syscall_handle_objdir(syscall_context_t *ctx) { switch(ctx->header->callid) { case SYSCALL_OBJDIR_OBJTYPE: if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_OBJTYPE) return s_syscall_objdir_objtype( ctx->objdir, ctx->target.obj, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_OBJDIR_SWAP: if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_SWAP) return s_syscall_objdir_swap(ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_OBJDIR_LINK: if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_LINK) return s_syscall_objdir_link(ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; default: return -EBADCALL; } }