summaryrefslogtreecommitdiffstats
path: root/src/plist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2019-08-09 19:59:05 +0200
committerGravatar Nikias Bassen2019-08-09 19:59:05 +0200
commite1a5d60e98b72fe110391da848c77cc36665bd66 (patch)
tree9b3f2bd9960aa0a2e17c8c6d53e53646d7638eec /src/plist.c
parent811a53aefe4693113ef723783c151e473853a398 (diff)
downloadlibplist-e1a5d60e98b72fe110391da848c77cc36665bd66.tar.gz
libplist-e1a5d60e98b72fe110391da848c77cc36665bd66.tar.bz2
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.
Diffstat (limited to 'src/plist.c')
-rw-r--r--src/plist.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/src/plist.c b/src/plist.c
index 6d7a07f..4600198 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -321,7 +321,7 @@ PLIST_API void plist_free(plist_t plist)
321 } 321 }
322} 322}
323 323
324static void plist_copy_node(node_t *node, void *parent_node_ptr) 324static plist_t plist_copy_node(node_t *node, void *parent_node_ptr)
325{ 325{
326 plist_type node_type = PLIST_NONE; 326 plist_type node_type = PLIST_NONE;
327 plist_t newnode = NULL; 327 plist_t newnode = NULL;
@@ -347,13 +347,6 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
347 if (data->hashtable) { 347 if (data->hashtable) {
348 ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity); 348 ptrarray_t* pa = ptr_array_new(((ptrarray_t*)data->hashtable)->capacity);
349 assert(pa); 349 assert(pa);
350 plist_t current = NULL;
351 for (current = (plist_t)node_first_child(node);
352 pa && current;
353 current = (plist_t)node_next_sibling(current))
354 {
355 ptr_array_add(pa, current);
356 }
357 newdata->hashtable = pa; 350 newdata->hashtable = pa;
358 } 351 }
359 break; 352 break;
@@ -361,13 +354,6 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
361 if (data->hashtable) { 354 if (data->hashtable) {
362 hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL); 355 hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
363 assert(ht); 356 assert(ht);
364 plist_t current = NULL;
365 for (current = (plist_t)node_first_child(node);
366 ht && current;
367 current = (plist_t)node_next_sibling(node_next_sibling(current)))
368 {
369 hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
370 }
371 newdata->hashtable = ht; 357 newdata->hashtable = ht;
372 } 358 }
373 break; 359 break;
@@ -386,16 +372,34 @@ static void plist_copy_node(node_t *node, void *parent_node_ptr)
386 } 372 }
387 373
388 node_t *ch; 374 node_t *ch;
375 unsigned int node_index = 0;
389 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { 376 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
390 plist_copy_node(ch, &newnode); 377 /* copy child node and attach to new parent node */
378 plist_t newch = plist_copy_node(ch, &newnode);
379 /* if needed, add child node to lookup table of parent node */
380 switch (node_type) {
381 case PLIST_ARRAY:
382 if (newdata->hashtable) {
383 ptr_array_add((ptrarray_t*)newdata->hashtable, newch);
384 }
385 break;
386 case PLIST_DICT:
387 if (newdata->hashtable && (node_index % 2 != 0)) {
388 hash_table_insert((hashtable_t*)newdata->hashtable, (node_prev_sibling((node_t*)newch))->data, newch);
389 }
390 break;
391 default:
392 break;
393 }
394 node_index++;
391 } 395 }
396 return newnode;
392} 397}
393 398
394PLIST_API plist_t plist_copy(plist_t node) 399PLIST_API plist_t plist_copy(plist_t node)
395{ 400{
396 plist_t copied = NULL; 401 plist_t copied = NULL;
397 plist_copy_node(node, &copied); 402 return plist_copy_node(node, &copied);
398 return copied;
399} 403}
400 404
401PLIST_API uint32_t plist_array_get_size(plist_t node) 405PLIST_API uint32_t plist_array_get_size(plist_t node)