kernel: handle: init handle table duplication
This commit is contained in:
@@ -44,6 +44,9 @@ struct handle_table {
|
|||||||
|
|
||||||
extern struct handle_table *handle_table_create(void);
|
extern struct handle_table *handle_table_create(void);
|
||||||
extern void handle_table_destroy(struct handle_table *tab);
|
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(
|
extern kern_status_t handle_table_alloc_handle(
|
||||||
struct handle_table *tab,
|
struct handle_table *tab,
|
||||||
|
|||||||
@@ -77,6 +77,81 @@ void handle_table_destroy(struct handle_table *tab)
|
|||||||
do_handle_table_destroy(tab, 0);
|
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(
|
static kern_status_t decode_handle_indices(
|
||||||
kern_handle_t handle,
|
kern_handle_t handle,
|
||||||
unsigned int indices[MAX_TABLE_DEPTH])
|
unsigned int indices[MAX_TABLE_DEPTH])
|
||||||
|
|||||||
@@ -468,6 +468,14 @@ kern_status_t sys_task_duplicate(
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
task_lock_irqsave(self, &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;
|
struct handle *child_handle_slot = NULL, *space_handle_slot = NULL;
|
||||||
kern_handle_t child_handle, space_handle;
|
kern_handle_t child_handle, space_handle;
|
||||||
status = handle_table_alloc_handle(
|
status = handle_table_alloc_handle(
|
||||||
@@ -476,6 +484,7 @@ kern_status_t sys_task_duplicate(
|
|||||||
&child_handle_slot,
|
&child_handle_slot,
|
||||||
&child_handle);
|
&child_handle);
|
||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
|
handle_table_destroy(child_handle_table);
|
||||||
task_unlock_irqrestore(self, flags);
|
task_unlock_irqrestore(self, flags);
|
||||||
put_current_task(self);
|
put_current_task(self);
|
||||||
return status;
|
return status;
|
||||||
@@ -487,6 +496,7 @@ kern_status_t sys_task_duplicate(
|
|||||||
&space_handle_slot,
|
&space_handle_slot,
|
||||||
&space_handle);
|
&space_handle);
|
||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
|
handle_table_destroy(child_handle_table);
|
||||||
handle_table_free_handle(self->t_handles, child_handle);
|
handle_table_free_handle(self->t_handles, child_handle);
|
||||||
task_unlock_irqrestore(self, flags);
|
task_unlock_irqrestore(self, flags);
|
||||||
put_current_task(self);
|
put_current_task(self);
|
||||||
|
|||||||
Reference in New Issue
Block a user