kernel: replace kern_handle_duplicate with the more powerful kern_handle_transfer

this syscall can move and copy handles within the current task, or from/to
other tasks
This commit is contained in:
2026-03-29 11:48:59 +01:00
parent 9001f8e064
commit 62770f4ab2
6 changed files with 128 additions and 20 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ static const virt_addr_t syscall_table[] = {
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_RELEASE, address_space_release),
SYSCALL_TABLE_ENTRY(KERN_LOG, kern_log),
SYSCALL_TABLE_ENTRY(KERN_HANDLE_CLOSE, kern_handle_close),
SYSCALL_TABLE_ENTRY(KERN_HANDLE_DUPLICATE, kern_handle_duplicate),
SYSCALL_TABLE_ENTRY(KERN_HANDLE_TRANSFER, kern_handle_transfer),
SYSCALL_TABLE_ENTRY(KERN_CONFIG_GET, kern_config_get),
SYSCALL_TABLE_ENTRY(KERN_CONFIG_SET, kern_config_set),
SYSCALL_TABLE_ENTRY(CHANNEL_CREATE, channel_create),
+111 -11
View File
@@ -8,32 +8,132 @@ kern_status_t sys_kern_handle_close(kern_handle_t handle)
return task_close_handle(self, handle);
}
kern_status_t sys_kern_handle_duplicate(
kern_handle_t handle,
kern_handle_t *out)
kern_status_t sys_kern_handle_transfer(
kern_handle_t src_task_handle,
kern_handle_t src_handle,
kern_handle_t dest_task_handle,
kern_handle_t dest_handle,
unsigned int mode,
kern_handle_t *out_handle)
{
switch (mode) {
case HANDLE_TRANSFER_MOVE:
case HANDLE_TRANSFER_COPY:
break;
default:
return KERN_INVALID_ARGUMENT;
}
struct task *self = current_task();
if (!validate_access_w(self, out, sizeof *out)) {
if (out_handle
&& !validate_access_w(self, out_handle, sizeof *out_handle)) {
return KERN_MEMORY_FAULT;
}
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *src_object = NULL;
struct task *src_task = NULL;
struct task *dest_task = NULL;
kern_status_t status = KERN_OK;
struct object *obj = NULL;
handle_flags_t handle_flags = 0;
kern_status_t status
= task_resolve_handle(self, handle, &obj, &handle_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
if (src_task_handle != KERN_HANDLE_INVALID) {
status = task_resolve_handle(
self,
src_task_handle,
&obj,
&handle_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
goto cleanup;
}
src_task = task_cast(obj);
if (!src_task) {
status = KERN_INVALID_ARGUMENT;
goto cleanup;
}
} else {
src_task = self;
}
status = task_open_handle(self, obj, handle_flags, out);
object_unref(obj);
if (dest_task_handle != KERN_HANDLE_INVALID) {
status = task_resolve_handle(
self,
dest_task_handle,
&obj,
&handle_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
goto cleanup;
}
dest_task = task_cast(obj);
if (!dest_task) {
status = KERN_INVALID_ARGUMENT;
goto cleanup;
}
} else {
dest_task = self;
}
status = task_resolve_handle(
self,
src_handle,
&src_object,
&handle_flags);
if (status != KERN_OK) {
goto cleanup;
}
task_unlock_irqrestore(self, flags);
struct handle *dest = NULL;
task_lock_irqsave(dest_task, &flags);
status = handle_table_alloc_handle(
dest_task->t_handles,
dest_handle,
&dest,
&dest_handle);
task_unlock_irqrestore(dest_task, flags);
if (status != KERN_OK) {
goto cleanup;
}
if (mode == HANDLE_TRANSFER_MOVE) {
object_ref(src_object);
task_lock_irqsave(src_task, &flags);
handle_table_free_handle(src_task->t_handles, src_handle);
task_unlock_irqrestore(src_task, flags);
}
dest->h_object = src_object;
dest->h_flags = handle_flags;
if (out_handle) {
*out_handle = dest_handle;
}
return KERN_OK;
cleanup:
if (src_task && src_task_handle != KERN_HANDLE_INVALID) {
object_unref(&src_task->t_base);
}
if (dest_task && dest_task_handle != KERN_HANDLE_INVALID) {
object_unref(&dest_task->t_base);
}
if (src_object) {
object_unref(src_object);
}
return status;
}