Commit e1a5d60e authored by Nikias Bassen's avatar Nikias Bassen

Make sure to copy hash table entries properly when cloning array/dict nodes

As mentioned in #142, plist_copy_node() was not correctly handling the hash
tables when cloning array or dict nodes; it incorrectly filled the hash table
with the original child node info, which effectively would lead to a
segmentation fault / UaF if the original array/dict would be freed followed
by an attempt to access an element in the new hash table.
parent 811a53ae
......@@ -321,7 +321,7 @@ PLIST_API void plist_free(plist_t plist)
}
}
static void plist_copy_node(node_t *node, void *parent_node_ptr)
static plist_t plist_copy_node(node_t *node, void *parent_node_ptr)
{
plist_type node_type = PLIST_NONE;
plist_t newnode = NULL;
......@@ -347,13 +347,6 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
if (data->hashtable) {
ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity);
assert(pa);
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
pa && current;
current = (plist_t)node_next_sibling(current))
{
ptr_array_add(pa, current);
}
newdata->hashtable = pa;
}
break;
......@@ -361,13 +354,6 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
if (data->hashtable) {
hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
assert(ht);
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
ht && current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
}
newdata->hashtable = ht;
}
break;
......@@ -386,16 +372,34 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
}
node_t *ch;
unsigned int node_index = 0;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
plist_copy_node(ch, &newnode);
/* copy child node and attach to new parent node */
plist_t newch = plist_copy_node(ch, &newnode);
/* if needed, add child node to lookup table of parent node */
switch (node_type) {
case PLIST_ARRAY:
if (newdata->hashtable) {
ptr_array_add((ptrarray_t*)newdata->hashtable, newch);
}
break;
case PLIST_DICT:
if (newdata->hashtable && (node_index % 2 != 0)) {
hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t*)newch))->data, newch);
}
break;
default:
break;
}
node_index++;
}
return newnode;
}
PLIST_API plist_t plist_copy(plist_t node)
{
plist_t copied = NULL;
plist_copy_node(node, &copied);
return copied;
return plist_copy_node(node, &copied);
}
PLIST_API uint32_t plist_array_get_size(plist_t node)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment