From f1dd9d8564bde7f76ddee53cf415ba895403cb58 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sun, 19 Apr 2026 20:07:51 +0100 Subject: [PATCH] kernel: handle: init handle table duplication --- include/kernel/handle.h | 3 ++ kernel/handle.c | 75 +++++++++++++++++++++++++++++++++++++++++ syscall/task.c | 10 ++++++ 3 files changed, 88 insertions(+) diff --git a/include/kernel/handle.h b/include/kernel/handle.h index d23d6eb..61c7ab3 100644 --- a/include/kernel/handle.h +++ b/include/kernel/handle.h @@ -44,6 +44,9 @@ struct handle_table { extern struct handle_table *handle_table_create(void); extern void handle_table_destroy(struct handle_table *tab); +extern kern_status_t handle_table_duplicate( + struct handle_table *src, + struct handle_table **dest); extern kern_status_t handle_table_alloc_handle( struct handle_table *tab, diff --git a/kernel/handle.c b/kernel/handle.c index fd043ac..633c8b7 100644 --- a/kernel/handle.c +++ b/kernel/handle.c @@ -77,6 +77,81 @@ void handle_table_destroy(struct handle_table *tab) do_handle_table_destroy(tab, 0); } +static kern_status_t do_handle_table_duplicate_leaf( + struct handle_table *src, + struct handle_table **dest) +{ + struct handle_table *out + = vm_cache_alloc(&handle_table_cache, VM_NORMAL); + if (!out) { + return KERN_NO_MEMORY; + } + + memcpy(out, src, sizeof *out); + + for (size_t i = 0; i < HANDLES_PER_TABLE; i++) { + struct object *obj = src->t_handles.t_handle_list[i].h_object; + if (obj) { + object_ref(obj); + } + } + + *dest = out; + return KERN_OK; +} + +static kern_status_t do_handle_table_duplicate( + struct handle_table *src, + struct handle_table **dest, + unsigned int depth) +{ + if (depth == MAX_TABLE_DEPTH - 1) { + return do_handle_table_duplicate_leaf(src, dest); + } + + struct handle_table *out + = vm_cache_alloc(&handle_table_cache, VM_NORMAL); + if (!out) { + return KERN_NO_MEMORY; + } + + memcpy(out->t_subtables.t_subtable_map, + src->t_subtables.t_subtable_map, + sizeof out->t_subtables.t_subtable_map); + memset(out->t_subtables.t_subtable_list, + 0x0, + sizeof out->t_subtables.t_subtable_list); + + for (size_t i = 0; i < REFS_PER_TABLE; i++) { + struct handle_table *child + = src->t_subtables.t_subtable_list[i]; + struct handle_table *dup = NULL; + kern_status_t status = KERN_OK; + if (child) { + status = do_handle_table_duplicate( + child, + &dup, + depth + 1); + } + + if (status == KERN_OK) { + out->t_subtables.t_subtable_list[i] = dup; + } else { + return status; + } + } + + *dest = out; + return KERN_OK; +} + +kern_status_t handle_table_duplicate( + struct handle_table *src, + struct handle_table **dest) +{ + return do_handle_table_duplicate(src, dest, 0); +} + static kern_status_t decode_handle_indices( kern_handle_t handle, unsigned int indices[MAX_TABLE_DEPTH]) diff --git a/syscall/task.c b/syscall/task.c index b348105..421ef84 100644 --- a/syscall/task.c +++ b/syscall/task.c @@ -468,6 +468,14 @@ kern_status_t sys_task_duplicate( unsigned long flags; task_lock_irqsave(self, &flags); + struct handle_table *child_handle_table = NULL; + status = handle_table_duplicate(self->t_handles, &child_handle_table); + if (status != KERN_OK) { + task_unlock_irqrestore(self, flags); + put_current_task(self); + return status; + } + struct handle *child_handle_slot = NULL, *space_handle_slot = NULL; kern_handle_t child_handle, space_handle; status = handle_table_alloc_handle( @@ -476,6 +484,7 @@ kern_status_t sys_task_duplicate( &child_handle_slot, &child_handle); if (status != KERN_OK) { + handle_table_destroy(child_handle_table); task_unlock_irqrestore(self, flags); put_current_task(self); return status; @@ -487,6 +496,7 @@ kern_status_t sys_task_duplicate( &space_handle_slot, &space_handle); if (status != KERN_OK) { + handle_table_destroy(child_handle_table); handle_table_free_handle(self->t_handles, child_handle); task_unlock_irqrestore(self, flags); put_current_task(self);