summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2017-02-04 02:51:03 +0100
committerGravatar Nikias Bassen2017-02-04 02:51:03 +0100
commitc4dcf11b533b1b604216edb295e4f50a6085650f (patch)
treee2c30b92f152d9cd9cf559b46198711d77aa0ce6
parentfc047e6de9d7afa3b168fd2c4d1d0884788e7086 (diff)
downloadlibplist-c4dcf11b533b1b604216edb295e4f50a6085650f.tar.gz
libplist-c4dcf11b533b1b604216edb295e4f50a6085650f.tar.bz2
bplist: Fix OOB write on heap buffer and improve recursion check
Issue #92 pointed out an problem with (invalid) bplist files which have exactly one structured node whose subnode reference itself. The recursion check used a fixed size array with the size of the total number of objects. In this case the number of objects is 1 but the recursion check code wanted to set the node_index for the level 1 which leads to an OOB write on the heap. This commit fixes/improves two things: 1) Prevent OOB write by using a dynamic data storage for the used node indexes (plist_t of type PLIST_ARRAY) 2) Reduces the memory usage of large binary plists, because not the total number of nodes in the binary plist, but the number of recursion levels is important for the recursion check.
-rw-r--r--src/bplist.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/bplist.c b/src/bplist.c
index 0cfe5fe..d2a1ccb 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -187,7 +187,7 @@ struct bplist_data {
187 uint8_t offset_size; 187 uint8_t offset_size;
188 const char* offset_table; 188 const char* offset_table;
189 uint32_t level; 189 uint32_t level;
190 uint32_t *used_indexes; 190 plist_t used_indexes;
191}; 191};
192 192
193static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index); 193static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index);
@@ -645,11 +645,20 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
645 } 645 }
646 646
647 /* store node_index for current recursion level */ 647 /* store node_index for current recursion level */
648 bplist->used_indexes[bplist->level] = node_index; 648 if (plist_array_get_size(bplist->used_indexes) < bplist->level+1) {
649 while (plist_array_get_size(bplist->used_indexes) < bplist->level+1) {
650 plist_array_append_item(bplist->used_indexes, plist_new_uint(node_index));
651 }
652 } else {
653 plist_array_set_item(bplist->used_indexes, plist_new_uint(node_index), bplist->level);
654 }
655
649 /* recursion check */ 656 /* recursion check */
650 if (bplist->level > 0) { 657 if (bplist->level > 0) {
651 for (i = bplist->level-1; i >= 0; i--) { 658 for (i = bplist->level-1; i >= 0; i--) {
652 if (bplist->used_indexes[i] == bplist->used_indexes[bplist->level]) { 659 plist_t node_i = plist_array_get_item(bplist->used_indexes, i);
660 plist_t node_level = plist_array_get_item(bplist->used_indexes, bplist->level);
661 if (plist_compare_node_value(node_i, node_level)) {
653 fprintf(stderr, "Recursion detected in binary plist. Aborting.\n"); 662 fprintf(stderr, "Recursion detected in binary plist. Aborting.\n");
654 return NULL; 663 return NULL;
655 } 664 }
@@ -709,9 +718,6 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
709 if (offset_table + num_objects * offset_size >= plist_bin + length) 718 if (offset_table + num_objects * offset_size >= plist_bin + length)
710 return; 719 return;
711 720
712 if (sizeof(uint32_t) * num_objects < num_objects)
713 return;
714
715 struct bplist_data bplist; 721 struct bplist_data bplist;
716 bplist.data = plist_bin; 722 bplist.data = plist_bin;
717 bplist.size = length; 723 bplist.size = length;
@@ -720,14 +726,14 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
720 bplist.offset_size = offset_size; 726 bplist.offset_size = offset_size;
721 bplist.offset_table = offset_table; 727 bplist.offset_table = offset_table;
722 bplist.level = 0; 728 bplist.level = 0;
723 bplist.used_indexes = (uint32_t*)malloc(sizeof(uint32_t) * num_objects); 729 bplist.used_indexes = plist_new_array();
724 730
725 if (!bplist.used_indexes) 731 if (!bplist.used_indexes)
726 return; 732 return;
727 733
728 *plist = parse_bin_node_at_index(&bplist, root_object); 734 *plist = parse_bin_node_at_index(&bplist, root_object);
729 735
730 free(bplist.used_indexes); 736 plist_free(bplist.used_indexes);
731} 737}
732 738
733static unsigned int plist_data_hash(const void* key) 739static unsigned int plist_data_hash(const void* key)