diff options
| author | 2026-01-17 15:18:06 +0100 | |
|---|---|---|
| committer | 2026-01-17 16:04:00 +0100 | |
| commit | e45099fb21b679aa0cdb0db394587bb5ba675b0c (patch) | |
| tree | b1a2c1dd34877d83a04d6d6fab804fb2e5a65f2d | |
| parent | 26dd27c435a0d110c924e1fef34ad0f6ae60e251 (diff) | |
| download | libplist-e45099fb21b679aa0cdb0db394587bb5ba675b0c.tar.gz libplist-e45099fb21b679aa0cdb0db394587bb5ba675b0c.tar.bz2 | |
Prevent deep nesting of plist structures in all input/output formats
Thanks to @unbengable12 for reporting. Addresses #288, #289, #290, #291, and #292.
| -rw-r--r-- | include/plist/plist.h | 1 | ||||
| -rw-r--r-- | src/bplist.c | 26 | ||||
| -rw-r--r-- | src/jplist.c | 48 | ||||
| -rw-r--r-- | src/oplist.c | 69 | ||||
| -rw-r--r-- | src/out-default.c | 7 | ||||
| -rw-r--r-- | src/out-limd.c | 7 | ||||
| -rw-r--r-- | src/out-plutil.c | 7 | ||||
| -rw-r--r-- | src/plist.h | 4 | ||||
| -rw-r--r-- | src/xplist.c | 111 |
9 files changed, 185 insertions, 95 deletions
diff --git a/include/plist/plist.h b/include/plist/plist.h index 5ea30b8..8ed9063 100644 --- a/include/plist/plist.h +++ b/include/plist/plist.h | |||
| @@ -145,6 +145,7 @@ extern "C" | |||
| 145 | PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */ | 145 | PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */ |
| 146 | PLIST_ERR_IO = -5, /**< I/O error */ | 146 | PLIST_ERR_IO = -5, /**< I/O error */ |
| 147 | PLIST_ERR_CIRCULAR_REF = -6, /**< circular reference detected */ | 147 | PLIST_ERR_CIRCULAR_REF = -6, /**< circular reference detected */ |
| 148 | PLIST_ERR_MAX_NESTING = -7, /**< maximum nesting depth exceeded */ | ||
| 148 | PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */ | 149 | PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */ |
| 149 | } plist_err_t; | 150 | } plist_err_t; |
| 150 | 151 | ||
diff --git a/src/bplist.c b/src/bplist.c index a2dc957..254c0ff 100644 --- a/src/bplist.c +++ b/src/bplist.c | |||
| @@ -239,6 +239,7 @@ struct bplist_data { | |||
| 239 | const char* offset_table; | 239 | const char* offset_table; |
| 240 | uint32_t level; | 240 | uint32_t level; |
| 241 | ptrarray_t* used_indexes; | 241 | ptrarray_t* used_indexes; |
| 242 | plist_err_t err; | ||
| 242 | }; | 243 | }; |
| 243 | 244 | ||
| 244 | #ifdef DEBUG | 245 | #ifdef DEBUG |
| @@ -787,6 +788,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node | |||
| 787 | 788 | ||
| 788 | if (node_index >= bplist->num_objects) { | 789 | if (node_index >= bplist->num_objects) { |
| 789 | PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%" PRIu64 ")\n", node_index, bplist->num_objects); | 790 | PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%" PRIu64 ")\n", node_index, bplist->num_objects); |
| 791 | bplist->err = PLIST_ERR_PARSE; | ||
| 790 | return NULL; | 792 | return NULL; |
| 791 | } | 793 | } |
| 792 | 794 | ||
| @@ -794,6 +796,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node | |||
| 794 | if (idx_ptr < bplist->offset_table || | 796 | if (idx_ptr < bplist->offset_table || |
| 795 | idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) { | 797 | idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) { |
| 796 | PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index); | 798 | PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index); |
| 799 | bplist->err = PLIST_ERR_PARSE; | ||
| 797 | return NULL; | 800 | return NULL; |
| 798 | } | 801 | } |
| 799 | 802 | ||
| @@ -801,6 +804,14 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node | |||
| 801 | /* make sure the node offset is in a sane range */ | 804 | /* make sure the node offset is in a sane range */ |
| 802 | if ((ptr < bplist->data+BPLIST_MAGIC_SIZE+BPLIST_VERSION_SIZE) || (ptr >= bplist->offset_table)) { | 805 | if ((ptr < bplist->data+BPLIST_MAGIC_SIZE+BPLIST_VERSION_SIZE) || (ptr >= bplist->offset_table)) { |
| 803 | PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index); | 806 | PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index); |
| 807 | bplist->err = PLIST_ERR_PARSE; | ||
| 808 | return NULL; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* check nesting depth */ | ||
| 812 | if (bplist->level > PLIST_MAX_NESTING_DEPTH) { | ||
| 813 | PLIST_BIN_ERR("maximum nesting depth (%u) exceeded\n",(unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 814 | bplist->err = PLIST_ERR_MAX_NESTING; | ||
| 804 | return NULL; | 815 | return NULL; |
| 805 | } | 816 | } |
| 806 | 817 | ||
| @@ -820,6 +831,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node | |||
| 820 | void *node_level = ptr_array_index(bplist->used_indexes, bplist->level); | 831 | void *node_level = ptr_array_index(bplist->used_indexes, bplist->level); |
| 821 | if (node_i == node_level) { | 832 | if (node_i == node_level) { |
| 822 | PLIST_BIN_ERR("recursion detected in binary plist\n"); | 833 | PLIST_BIN_ERR("recursion detected in binary plist\n"); |
| 834 | bplist->err = PLIST_ERR_PARSE; | ||
| 823 | return NULL; | 835 | return NULL; |
| 824 | } | 836 | } |
| 825 | } | 837 | } |
| @@ -931,6 +943,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli | |||
| 931 | bplist.offset_table = offset_table; | 943 | bplist.offset_table = offset_table; |
| 932 | bplist.level = 0; | 944 | bplist.level = 0; |
| 933 | bplist.used_indexes = ptr_array_new(16); | 945 | bplist.used_indexes = ptr_array_new(16); |
| 946 | bplist.err = PLIST_ERR_SUCCESS; | ||
| 934 | 947 | ||
| 935 | if (!bplist.used_indexes) { | 948 | if (!bplist.used_indexes) { |
| 936 | PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n"); | 949 | PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n"); |
| @@ -942,7 +955,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli | |||
| 942 | ptr_array_free(bplist.used_indexes); | 955 | ptr_array_free(bplist.used_indexes); |
| 943 | 956 | ||
| 944 | if (!*plist) { | 957 | if (!*plist) { |
| 945 | return PLIST_ERR_PARSE; | 958 | return (bplist.err != PLIST_ERR_SUCCESS) ? bplist.err : PLIST_ERR_PARSE; |
| 946 | } | 959 | } |
| 947 | 960 | ||
| 948 | return PLIST_ERR_SUCCESS; | 961 | return PLIST_ERR_SUCCESS; |
| @@ -1002,11 +1015,16 @@ struct serialize_s | |||
| 1002 | hashtable_t* in_stack; | 1015 | hashtable_t* in_stack; |
| 1003 | }; | 1016 | }; |
| 1004 | 1017 | ||
| 1005 | static plist_err_t serialize_plist(node_t node, void* data) | 1018 | static plist_err_t serialize_plist(node_t node, void* data, uint32_t depth) |
| 1006 | { | 1019 | { |
| 1007 | uint64_t *index_val = NULL; | 1020 | uint64_t *index_val = NULL; |
| 1008 | struct serialize_s *ser = (struct serialize_s *) data; | 1021 | struct serialize_s *ser = (struct serialize_s *) data; |
| 1009 | 1022 | ||
| 1023 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 1024 | PLIST_BIN_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 1025 | return PLIST_ERR_MAX_NESTING; | ||
| 1026 | } | ||
| 1027 | |||
| 1010 | // circular reference check: is node on current recursion stack? | 1028 | // circular reference check: is node on current recursion stack? |
| 1011 | if (hash_table_lookup(ser->in_stack, node)) { | 1029 | if (hash_table_lookup(ser->in_stack, node)) { |
| 1012 | PLIST_BIN_WRITE_ERR("circular reference detected\n"); | 1030 | PLIST_BIN_WRITE_ERR("circular reference detected\n"); |
| @@ -1036,7 +1054,7 @@ static plist_err_t serialize_plist(node_t node, void* data) | |||
| 1036 | node_t ch; | 1054 | node_t ch; |
| 1037 | plist_err_t err = PLIST_ERR_SUCCESS; | 1055 | plist_err_t err = PLIST_ERR_SUCCESS; |
| 1038 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | 1056 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { |
| 1039 | err = serialize_plist(ch, data); | 1057 | err = serialize_plist(ch, data, depth+1); |
| 1040 | if (err != PLIST_ERR_SUCCESS) { | 1058 | if (err != PLIST_ERR_SUCCESS) { |
| 1041 | break; | 1059 | break; |
| 1042 | } | 1060 | } |
| @@ -1313,7 +1331,7 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 1313 | ser_s.objects = objects; | 1331 | ser_s.objects = objects; |
| 1314 | ser_s.ref_table = ref_table; | 1332 | ser_s.ref_table = ref_table; |
| 1315 | ser_s.in_stack = in_stack; | 1333 | ser_s.in_stack = in_stack; |
| 1316 | plist_err_t err = serialize_plist((node_t)plist, &ser_s); | 1334 | plist_err_t err = serialize_plist((node_t)plist, &ser_s, 0); |
| 1317 | if (err != PLIST_ERR_SUCCESS) { | 1335 | if (err != PLIST_ERR_SUCCESS) { |
| 1318 | ptr_array_free(objects); | 1336 | ptr_array_free(objects); |
| 1319 | hash_table_destroy(ref_table); | 1337 | hash_table_destroy(ref_table); |
diff --git a/src/jplist.c b/src/jplist.c index 2e53400..9a40844 100644 --- a/src/jplist.c +++ b/src/jplist.c | |||
| @@ -323,6 +323,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 323 | return PLIST_ERR_INVALID_ARG; | 323 | return PLIST_ERR_INVALID_ARG; |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 327 | PLIST_JSON_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 328 | return PLIST_ERR_MAX_NESTING; | ||
| 329 | } | ||
| 330 | |||
| 326 | if (hash_table_lookup(visited, node)) { | 331 | if (hash_table_lookup(visited, node)) { |
| 327 | PLIST_JSON_WRITE_ERR("circular reference detected\n"); | 332 | PLIST_JSON_WRITE_ERR("circular reference detected\n"); |
| 328 | return PLIST_ERR_CIRCULAR_REF; | 333 | return PLIST_ERR_CIRCULAR_REF; |
| @@ -471,6 +476,7 @@ plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, in | |||
| 471 | typedef struct { | 476 | typedef struct { |
| 472 | jsmntok_t* tokens; | 477 | jsmntok_t* tokens; |
| 473 | int count; | 478 | int count; |
| 479 | plist_err_t err; | ||
| 474 | } jsmntok_info_t; | 480 | } jsmntok_info_t; |
| 475 | 481 | ||
| 476 | static int64_t parse_decimal(const char* str, const char* str_end, char** endp) | 482 | static int64_t parse_decimal(const char* str, const char* str_end, char** endp) |
| @@ -698,12 +704,18 @@ static plist_t parse_string(const char* js, jsmntok_info_t* ti, int* index) | |||
| 698 | return node; | 704 | return node; |
| 699 | } | 705 | } |
| 700 | 706 | ||
| 701 | static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index); | 707 | static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth); |
| 702 | 708 | ||
| 703 | static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) | 709 | static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth) |
| 704 | { | 710 | { |
| 705 | if (ti->tokens[*index].type != JSMN_ARRAY) { | 711 | if (ti->tokens[*index].type != JSMN_ARRAY) { |
| 706 | PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__); | 712 | PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__); |
| 713 | ti->err = PLIST_ERR_PARSE; | ||
| 714 | return NULL; | ||
| 715 | } | ||
| 716 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 717 | PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 718 | ti->err = PLIST_ERR_MAX_NESTING; | ||
| 707 | return NULL; | 719 | return NULL; |
| 708 | } | 720 | } |
| 709 | plist_t arr = plist_new_array(); | 721 | plist_t arr = plist_new_array(); |
| @@ -714,15 +726,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) | |||
| 714 | if (j >= ti->count) { | 726 | if (j >= ti->count) { |
| 715 | PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); | 727 | PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); |
| 716 | plist_free(arr); | 728 | plist_free(arr); |
| 729 | ti->err = PLIST_ERR_PARSE; | ||
| 717 | return NULL; | 730 | return NULL; |
| 718 | } | 731 | } |
| 719 | plist_t val = NULL; | 732 | plist_t val = NULL; |
| 720 | switch (ti->tokens[j].type) { | 733 | switch (ti->tokens[j].type) { |
| 721 | case JSMN_OBJECT: | 734 | case JSMN_OBJECT: |
| 722 | val = parse_object(js, ti, &j); | 735 | val = parse_object(js, ti, &j, depth+1); |
| 723 | break; | 736 | break; |
| 724 | case JSMN_ARRAY: | 737 | case JSMN_ARRAY: |
| 725 | val = parse_array(js, ti, &j); | 738 | val = parse_array(js, ti, &j, depth+1); |
| 726 | break; | 739 | break; |
| 727 | case JSMN_STRING: | 740 | case JSMN_STRING: |
| 728 | val = parse_string(js, ti, &j); | 741 | val = parse_string(js, ti, &j); |
| @@ -737,6 +750,7 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) | |||
| 737 | plist_array_append_item(arr, val); | 750 | plist_array_append_item(arr, val); |
| 738 | } else { | 751 | } else { |
| 739 | plist_free(arr); | 752 | plist_free(arr); |
| 753 | ti->err = PLIST_ERR_PARSE; | ||
| 740 | return NULL; | 754 | return NULL; |
| 741 | } | 755 | } |
| 742 | } | 756 | } |
| @@ -744,10 +758,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) | |||
| 744 | return arr; | 758 | return arr; |
| 745 | } | 759 | } |
| 746 | 760 | ||
| 747 | static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) | 761 | static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth) |
| 748 | { | 762 | { |
| 749 | if (ti->tokens[*index].type != JSMN_OBJECT) { | 763 | if (ti->tokens[*index].type != JSMN_OBJECT) { |
| 750 | PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__); | 764 | PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__); |
| 765 | ti->err = PLIST_ERR_PARSE; | ||
| 766 | return NULL; | ||
| 767 | } | ||
| 768 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 769 | PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 770 | ti->err = PLIST_ERR_MAX_NESTING; | ||
| 751 | return NULL; | 771 | return NULL; |
| 752 | } | 772 | } |
| 753 | int num_tokens = ti->tokens[*index].size; | 773 | int num_tokens = ti->tokens[*index].size; |
| @@ -755,6 +775,7 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) | |||
| 755 | int j = (*index)+1; | 775 | int j = (*index)+1; |
| 756 | if (num_tokens % 2 != 0) { | 776 | if (num_tokens % 2 != 0) { |
| 757 | PLIST_JSON_ERR("%s: number of children must be even\n", __func__); | 777 | PLIST_JSON_ERR("%s: number of children must be even\n", __func__); |
| 778 | ti->err = PLIST_ERR_PARSE; | ||
| 758 | return NULL; | 779 | return NULL; |
| 759 | } | 780 | } |
| 760 | plist_t obj = plist_new_dict(); | 781 | plist_t obj = plist_new_dict(); |
| @@ -762,12 +783,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) | |||
| 762 | if (j+1 >= ti->count) { | 783 | if (j+1 >= ti->count) { |
| 763 | PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); | 784 | PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); |
| 764 | plist_free(obj); | 785 | plist_free(obj); |
| 786 | ti->err = PLIST_ERR_PARSE; | ||
| 765 | return NULL; | 787 | return NULL; |
| 766 | } | 788 | } |
| 767 | if (ti->tokens[j].type == JSMN_STRING) { | 789 | if (ti->tokens[j].type == JSMN_STRING) { |
| 768 | char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL); | 790 | char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL); |
| 769 | if (!key) { | 791 | if (!key) { |
| 770 | plist_free(obj); | 792 | plist_free(obj); |
| 793 | ti->err = PLIST_ERR_PARSE; | ||
| 771 | return NULL; | 794 | return NULL; |
| 772 | } | 795 | } |
| 773 | plist_t val = NULL; | 796 | plist_t val = NULL; |
| @@ -775,10 +798,10 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) | |||
| 775 | num++; | 798 | num++; |
| 776 | switch (ti->tokens[j].type) { | 799 | switch (ti->tokens[j].type) { |
| 777 | case JSMN_OBJECT: | 800 | case JSMN_OBJECT: |
| 778 | val = parse_object(js, ti, &j); | 801 | val = parse_object(js, ti, &j, depth+1); |
| 779 | break; | 802 | break; |
| 780 | case JSMN_ARRAY: | 803 | case JSMN_ARRAY: |
| 781 | val = parse_array(js, ti, &j); | 804 | val = parse_array(js, ti, &j, depth+1); |
| 782 | break; | 805 | break; |
| 783 | case JSMN_STRING: | 806 | case JSMN_STRING: |
| 784 | val = parse_string(js, ti, &j); | 807 | val = parse_string(js, ti, &j); |
| @@ -794,12 +817,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) | |||
| 794 | } else { | 817 | } else { |
| 795 | free(key); | 818 | free(key); |
| 796 | plist_free(obj); | 819 | plist_free(obj); |
| 820 | ti->err = PLIST_ERR_PARSE; | ||
| 797 | return NULL; | 821 | return NULL; |
| 798 | } | 822 | } |
| 799 | free(key); | 823 | free(key); |
| 800 | } else { | 824 | } else { |
| 801 | PLIST_JSON_ERR("%s: keys must be of type STRING\n", __func__); | 825 | PLIST_JSON_ERR("%s: keys must be of type STRING\n", __func__); |
| 802 | plist_free(obj); | 826 | plist_free(obj); |
| 827 | ti->err = PLIST_ERR_PARSE; | ||
| 803 | return NULL; | 828 | return NULL; |
| 804 | } | 829 | } |
| 805 | } | 830 | } |
| @@ -859,7 +884,7 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) | |||
| 859 | } | 884 | } |
| 860 | 885 | ||
| 861 | int startindex = 0; | 886 | int startindex = 0; |
| 862 | jsmntok_info_t ti = { tokens, parser.toknext }; | 887 | jsmntok_info_t ti = { tokens, parser.toknext, PLIST_ERR_SUCCESS }; |
| 863 | switch (tokens[startindex].type) { | 888 | switch (tokens[startindex].type) { |
| 864 | case JSMN_PRIMITIVE: | 889 | case JSMN_PRIMITIVE: |
| 865 | *plist = parse_primitive(json, &ti, &startindex); | 890 | *plist = parse_primitive(json, &ti, &startindex); |
| @@ -868,14 +893,17 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) | |||
| 868 | *plist = parse_string(json, &ti, &startindex); | 893 | *plist = parse_string(json, &ti, &startindex); |
| 869 | break; | 894 | break; |
| 870 | case JSMN_ARRAY: | 895 | case JSMN_ARRAY: |
| 871 | *plist = parse_array(json, &ti, &startindex); | 896 | *plist = parse_array(json, &ti, &startindex, 0); |
| 872 | break; | 897 | break; |
| 873 | case JSMN_OBJECT: | 898 | case JSMN_OBJECT: |
| 874 | *plist = parse_object(json, &ti, &startindex); | 899 | *plist = parse_object(json, &ti, &startindex, 0); |
| 875 | break; | 900 | break; |
| 876 | default: | 901 | default: |
| 877 | break; | 902 | break; |
| 878 | } | 903 | } |
| 879 | free(tokens); | 904 | free(tokens); |
| 905 | if (!*plist) { | ||
| 906 | return (ti.err != PLIST_ERR_SUCCESS) ? ti.err : PLIST_ERR_PARSE; | ||
| 907 | } | ||
| 880 | return PLIST_ERR_SUCCESS; | 908 | return PLIST_ERR_SUCCESS; |
| 881 | } | 909 | } |
diff --git a/src/oplist.c b/src/oplist.c index 680873c..0eea27a 100644 --- a/src/oplist.c +++ b/src/oplist.c | |||
| @@ -367,6 +367,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 367 | return PLIST_ERR_INVALID_ARG; | 367 | return PLIST_ERR_INVALID_ARG; |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 371 | PLIST_OSTEP_WRITE_ERR("node tree is nested too deeply\n"); | ||
| 372 | return PLIST_ERR_MAX_NESTING; | ||
| 373 | } | ||
| 374 | |||
| 370 | if (hash_table_lookup(visited, node)) { | 375 | if (hash_table_lookup(visited, node)) { |
| 371 | PLIST_OSTEP_WRITE_ERR("circular reference detected\n"); | 376 | PLIST_OSTEP_WRITE_ERR("circular reference detected\n"); |
| 372 | return PLIST_ERR_CIRCULAR_REF; | 377 | return PLIST_ERR_CIRCULAR_REF; |
| @@ -511,7 +516,7 @@ struct _parse_ctx { | |||
| 511 | const char *start; | 516 | const char *start; |
| 512 | const char *pos; | 517 | const char *pos; |
| 513 | const char *end; | 518 | const char *end; |
| 514 | int err; | 519 | plist_err_t err; |
| 515 | uint32_t depth; | 520 | uint32_t depth; |
| 516 | }; | 521 | }; |
| 517 | typedef struct _parse_ctx* parse_ctx; | 522 | typedef struct _parse_ctx* parse_ctx; |
| @@ -568,50 +573,50 @@ static void parse_dict_data(parse_ctx ctx, plist_t dict) | |||
| 568 | } | 573 | } |
| 569 | key = NULL; | 574 | key = NULL; |
| 570 | ctx->err = node_from_openstep(ctx, &key); | 575 | ctx->err = node_from_openstep(ctx, &key); |
| 571 | if (ctx->err != 0) { | 576 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 572 | break; | 577 | break; |
| 573 | } | 578 | } |
| 574 | if (!PLIST_IS_STRING(key)) { | 579 | if (!PLIST_IS_STRING(key)) { |
| 575 | PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 580 | PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 576 | ctx->err++; | 581 | ctx->err = PLIST_ERR_PARSE; |
| 577 | break; | 582 | break; |
| 578 | } | 583 | } |
| 579 | parse_skip_ws(ctx); | 584 | parse_skip_ws(ctx); |
| 580 | if (ctx->pos >= ctx->end) { | 585 | if (ctx->pos >= ctx->end) { |
| 581 | PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 586 | PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 582 | ctx->err++; | 587 | ctx->err = PLIST_ERR_PARSE; |
| 583 | break; | 588 | break; |
| 584 | } | 589 | } |
| 585 | if (*ctx->pos != '=') { | 590 | if (*ctx->pos != '=') { |
| 586 | PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 591 | PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 587 | ctx->err++; | 592 | ctx->err = PLIST_ERR_PARSE; |
| 588 | break; | 593 | break; |
| 589 | } | 594 | } |
| 590 | ctx->pos++; | 595 | ctx->pos++; |
| 591 | if (ctx->pos >= ctx->end) { | 596 | if (ctx->pos >= ctx->end) { |
| 592 | PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 597 | PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 593 | ctx->err++; | 598 | ctx->err = PLIST_ERR_PARSE; |
| 594 | break; | 599 | break; |
| 595 | } | 600 | } |
| 596 | val = NULL; | 601 | val = NULL; |
| 597 | ctx->err = node_from_openstep(ctx, &val); | 602 | ctx->err = node_from_openstep(ctx, &val); |
| 598 | if (ctx->err != 0) { | 603 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 599 | break; | 604 | break; |
| 600 | } | 605 | } |
| 601 | if (!val) { | 606 | if (!val) { |
| 602 | PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 607 | PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 603 | ctx->err++; | 608 | ctx->err = PLIST_ERR_PARSE; |
| 604 | break; | 609 | break; |
| 605 | } | 610 | } |
| 606 | parse_skip_ws(ctx); | 611 | parse_skip_ws(ctx); |
| 607 | if (ctx->pos >= ctx->end) { | 612 | if (ctx->pos >= ctx->end) { |
| 608 | PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 613 | PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 609 | ctx->err++; | 614 | ctx->err = PLIST_ERR_PARSE; |
| 610 | break; | 615 | break; |
| 611 | } | 616 | } |
| 612 | if (*ctx->pos != ';') { | 617 | if (*ctx->pos != ';') { |
| 613 | PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 618 | PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 614 | ctx->err++; | 619 | ctx->err = PLIST_ERR_PARSE; |
| 615 | break; | 620 | break; |
| 616 | } | 621 | } |
| 617 | 622 | ||
| @@ -631,10 +636,10 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 631 | plist_t subnode = NULL; | 636 | plist_t subnode = NULL; |
| 632 | const char *p = NULL; | 637 | const char *p = NULL; |
| 633 | ctx->depth++; | 638 | ctx->depth++; |
| 634 | if (ctx->depth > 1000) { | 639 | if (ctx->depth > PLIST_MAX_NESTING_DEPTH) { |
| 635 | PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start)); | 640 | PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start)); |
| 636 | ctx->err++; | 641 | ctx->err = PLIST_ERR_MAX_NESTING; |
| 637 | return PLIST_ERR_PARSE; | 642 | return ctx->err; |
| 638 | } | 643 | } |
| 639 | while (ctx->pos < ctx->end && !ctx->err) { | 644 | while (ctx->pos < ctx->end && !ctx->err) { |
| 640 | parse_skip_ws(ctx); | 645 | parse_skip_ws(ctx); |
| @@ -652,12 +657,12 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 652 | } | 657 | } |
| 653 | if (ctx->pos >= ctx->end) { | 658 | if (ctx->pos >= ctx->end) { |
| 654 | PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 659 | PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 655 | ctx->err++; | 660 | ctx->err = PLIST_ERR_PARSE; |
| 656 | break; | 661 | break; |
| 657 | } | 662 | } |
| 658 | if (*ctx->pos != '}') { | 663 | if (*ctx->pos != '}') { |
| 659 | PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 664 | PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 660 | ctx->err++; | 665 | ctx->err = PLIST_ERR_PARSE; |
| 661 | goto err_out; | 666 | goto err_out; |
| 662 | } | 667 | } |
| 663 | ctx->pos++; | 668 | ctx->pos++; |
| @@ -675,11 +680,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 675 | break; | 680 | break; |
| 676 | } | 681 | } |
| 677 | ctx->err = node_from_openstep(ctx, &tmp); | 682 | ctx->err = node_from_openstep(ctx, &tmp); |
| 678 | if (ctx->err != 0) { | 683 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 679 | break; | 684 | break; |
| 680 | } | 685 | } |
| 681 | if (!tmp) { | 686 | if (!tmp) { |
| 682 | ctx->err++; | 687 | ctx->err = PLIST_ERR_PARSE; |
| 683 | break; | 688 | break; |
| 684 | } | 689 | } |
| 685 | plist_array_append_item(subnode, tmp); | 690 | plist_array_append_item(subnode, tmp); |
| @@ -687,7 +692,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 687 | parse_skip_ws(ctx); | 692 | parse_skip_ws(ctx); |
| 688 | if (ctx->pos >= ctx->end) { | 693 | if (ctx->pos >= ctx->end) { |
| 689 | PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 694 | PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 690 | ctx->err++; | 695 | ctx->err = PLIST_ERR_PARSE; |
| 691 | break; | 696 | break; |
| 692 | } | 697 | } |
| 693 | if (*ctx->pos != ',') { | 698 | if (*ctx->pos != ',') { |
| @@ -697,17 +702,17 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 697 | } | 702 | } |
| 698 | plist_free(tmp); | 703 | plist_free(tmp); |
| 699 | tmp = NULL; | 704 | tmp = NULL; |
| 700 | if (ctx->err) { | 705 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 701 | goto err_out; | 706 | goto err_out; |
| 702 | } | 707 | } |
| 703 | if (ctx->pos >= ctx->end) { | 708 | if (ctx->pos >= ctx->end) { |
| 704 | PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 709 | PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 705 | ctx->err++; | 710 | ctx->err = PLIST_ERR_PARSE; |
| 706 | break; | 711 | break; |
| 707 | } | 712 | } |
| 708 | if (*ctx->pos != ')') { | 713 | if (*ctx->pos != ')') { |
| 709 | PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 714 | PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 710 | ctx->err++; | 715 | ctx->err = PLIST_ERR_PARSE; |
| 711 | goto err_out; | 716 | goto err_out; |
| 712 | } | 717 | } |
| 713 | ctx->pos++; | 718 | ctx->pos++; |
| @@ -722,7 +727,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 722 | parse_skip_ws(ctx); | 727 | parse_skip_ws(ctx); |
| 723 | if (ctx->pos >= ctx->end) { | 728 | if (ctx->pos >= ctx->end) { |
| 724 | PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 729 | PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 725 | ctx->err++; | 730 | ctx->err = PLIST_ERR_PARSE; |
| 726 | break; | 731 | break; |
| 727 | } | 732 | } |
| 728 | if (*ctx->pos == '>') { | 733 | if (*ctx->pos == '>') { |
| @@ -730,19 +735,19 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 730 | } | 735 | } |
| 731 | if (!isxdigit(*ctx->pos)) { | 736 | if (!isxdigit(*ctx->pos)) { |
| 732 | PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 737 | PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 733 | ctx->err++; | 738 | ctx->err = PLIST_ERR_PARSE; |
| 734 | break; | 739 | break; |
| 735 | } | 740 | } |
| 736 | uint8_t b = HEX_DIGIT(*ctx->pos); | 741 | uint8_t b = HEX_DIGIT(*ctx->pos); |
| 737 | ctx->pos++; | 742 | ctx->pos++; |
| 738 | if (ctx->pos >= ctx->end) { | 743 | if (ctx->pos >= ctx->end) { |
| 739 | PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 744 | PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 740 | ctx->err++; | 745 | ctx->err = PLIST_ERR_PARSE; |
| 741 | break; | 746 | break; |
| 742 | } | 747 | } |
| 743 | if (!isxdigit(*ctx->pos)) { | 748 | if (!isxdigit(*ctx->pos)) { |
| 744 | PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 749 | PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 745 | ctx->err++; | 750 | ctx->err = PLIST_ERR_PARSE; |
| 746 | break; | 751 | break; |
| 747 | } | 752 | } |
| 748 | b = (b << 4) + HEX_DIGIT(*ctx->pos); | 753 | b = (b << 4) + HEX_DIGIT(*ctx->pos); |
| @@ -758,14 +763,14 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 758 | byte_array_free(bytes); | 763 | byte_array_free(bytes); |
| 759 | plist_free_data(data); | 764 | plist_free_data(data); |
| 760 | PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 765 | PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 761 | ctx->err++; | 766 | ctx->err = PLIST_ERR_PARSE; |
| 762 | goto err_out; | 767 | goto err_out; |
| 763 | } | 768 | } |
| 764 | if (*ctx->pos != '>') { | 769 | if (*ctx->pos != '>') { |
| 765 | byte_array_free(bytes); | 770 | byte_array_free(bytes); |
| 766 | plist_free_data(data); | 771 | plist_free_data(data); |
| 767 | PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 772 | PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 768 | ctx->err++; | 773 | ctx->err = PLIST_ERR_PARSE; |
| 769 | goto err_out; | 774 | goto err_out; |
| 770 | } | 775 | } |
| 771 | ctx->pos++; | 776 | ctx->pos++; |
| @@ -793,13 +798,13 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 793 | if (ctx->pos >= ctx->end) { | 798 | if (ctx->pos >= ctx->end) { |
| 794 | plist_free_data(data); | 799 | plist_free_data(data); |
| 795 | PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 800 | PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 796 | ctx->err++; | 801 | ctx->err = PLIST_ERR_PARSE; |
| 797 | goto err_out; | 802 | goto err_out; |
| 798 | } | 803 | } |
| 799 | if (*ctx->pos != c) { | 804 | if (*ctx->pos != c) { |
| 800 | plist_free_data(data); | 805 | plist_free_data(data); |
| 801 | PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start)); | 806 | PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start)); |
| 802 | ctx->err++; | 807 | ctx->err = PLIST_ERR_PARSE; |
| 803 | goto err_out; | 808 | goto err_out; |
| 804 | } | 809 | } |
| 805 | size_t slen = ctx->pos - p; | 810 | size_t slen = ctx->pos - p; |
| @@ -900,7 +905,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 900 | } else { | 905 | } else { |
| 901 | plist_free_data(data); | 906 | plist_free_data(data); |
| 902 | PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); | 907 | PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); |
| 903 | ctx->err++; | 908 | ctx->err = PLIST_ERR_PARSE; |
| 904 | break; | 909 | break; |
| 905 | } | 910 | } |
| 906 | } | 911 | } |
| @@ -909,11 +914,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist) | |||
| 909 | ctx->depth--; | 914 | ctx->depth--; |
| 910 | 915 | ||
| 911 | err_out: | 916 | err_out: |
| 912 | if (ctx->err) { | 917 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 913 | plist_free(subnode); | 918 | plist_free(subnode); |
| 914 | plist_free(*plist); | 919 | plist_free(*plist); |
| 915 | *plist = NULL; | 920 | *plist = NULL; |
| 916 | return PLIST_ERR_PARSE; | 921 | return ctx->err; |
| 917 | } | 922 | } |
| 918 | return PLIST_ERR_SUCCESS; | 923 | return PLIST_ERR_SUCCESS; |
| 919 | } | 924 | } |
diff --git a/src/out-default.c b/src/out-default.c index 09e64c3..fb57bcf 100644 --- a/src/out-default.c +++ b/src/out-default.c | |||
| @@ -318,6 +318,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 318 | return PLIST_ERR_INVALID_ARG; | 318 | return PLIST_ERR_INVALID_ARG; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 322 | #if DEBUG | ||
| 323 | fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 324 | #endif | ||
| 325 | return PLIST_ERR_MAX_NESTING; | ||
| 326 | } | ||
| 327 | |||
| 321 | if (hash_table_lookup(visited, node)) { | 328 | if (hash_table_lookup(visited, node)) { |
| 322 | #if DEBUG | 329 | #if DEBUG |
| 323 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); | 330 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); |
diff --git a/src/out-limd.c b/src/out-limd.c index e281644..35247fb 100644 --- a/src/out-limd.c +++ b/src/out-limd.c | |||
| @@ -286,6 +286,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 286 | return PLIST_ERR_INVALID_ARG; | 286 | return PLIST_ERR_INVALID_ARG; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 290 | #if DEBUG | ||
| 291 | fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 292 | #endif | ||
| 293 | return PLIST_ERR_MAX_NESTING; | ||
| 294 | } | ||
| 295 | |||
| 289 | if (hash_table_lookup(visited, node)) { | 296 | if (hash_table_lookup(visited, node)) { |
| 290 | #if DEBUG | 297 | #if DEBUG |
| 291 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); | 298 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); |
diff --git a/src/out-plutil.c b/src/out-plutil.c index 5354aa3..bf9e72e 100644 --- a/src/out-plutil.c +++ b/src/out-plutil.c | |||
| @@ -312,6 +312,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 312 | return PLIST_ERR_INVALID_ARG; | 312 | return PLIST_ERR_INVALID_ARG; |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 316 | #if DEBUG | ||
| 317 | fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 318 | #endif | ||
| 319 | return PLIST_ERR_MAX_NESTING; | ||
| 320 | } | ||
| 321 | |||
| 315 | if (hash_table_lookup(visited, node)) { | 322 | if (hash_table_lookup(visited, node)) { |
| 316 | #if DEBUG | 323 | #if DEBUG |
| 317 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); | 324 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); |
diff --git a/src/plist.h b/src/plist.h index 3043fb7..e310bcc 100644 --- a/src/plist.h +++ b/src/plist.h | |||
| @@ -49,6 +49,10 @@ | |||
| 49 | #endif | 49 | #endif |
| 50 | #endif | 50 | #endif |
| 51 | 51 | ||
| 52 | #ifndef PLIST_MAX_NESTING_DEPTH | ||
| 53 | #define PLIST_MAX_NESTING_DEPTH 512 | ||
| 54 | #endif | ||
| 55 | |||
| 52 | #include "plist/plist.h" | 56 | #include "plist/plist.h" |
| 53 | 57 | ||
| 54 | struct plist_data_s | 58 | struct plist_data_s |
diff --git a/src/xplist.c b/src/xplist.c index c25c6b9..9870104 100644 --- a/src/xplist.c +++ b/src/xplist.c | |||
| @@ -452,6 +452,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep | |||
| 452 | return PLIST_ERR_INVALID_ARG; | 452 | return PLIST_ERR_INVALID_ARG; |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | if (depth > PLIST_MAX_NESTING_DEPTH) { | ||
| 456 | PLIST_XML_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 457 | return PLIST_ERR_MAX_NESTING; | ||
| 458 | } | ||
| 459 | |||
| 455 | if (hash_table_lookup(visited, node)) { | 460 | if (hash_table_lookup(visited, node)) { |
| 456 | PLIST_XML_WRITE_ERR("circular reference detected\n"); | 461 | PLIST_XML_WRITE_ERR("circular reference detected\n"); |
| 457 | return PLIST_ERR_CIRCULAR_REF; | 462 | return PLIST_ERR_CIRCULAR_REF; |
| @@ -596,7 +601,7 @@ plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) | |||
| 596 | struct _parse_ctx { | 601 | struct _parse_ctx { |
| 597 | const char *pos; | 602 | const char *pos; |
| 598 | const char *end; | 603 | const char *end; |
| 599 | int err; | 604 | plist_err_t err; |
| 600 | }; | 605 | }; |
| 601 | typedef struct _parse_ctx* parse_ctx; | 606 | typedef struct _parse_ctx* parse_ctx; |
| 602 | 607 | ||
| @@ -720,21 +725,21 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 720 | find_char(ctx, '<', 0); | 725 | find_char(ctx, '<', 0); |
| 721 | if (ctx->pos >= ctx->end || *ctx->pos != '<') { | 726 | if (ctx->pos >= ctx->end || *ctx->pos != '<') { |
| 722 | PLIST_XML_ERR("EOF while looking for closing tag\n"); | 727 | PLIST_XML_ERR("EOF while looking for closing tag\n"); |
| 723 | ctx->err++; | 728 | ctx->err = PLIST_ERR_PARSE; |
| 724 | return NULL; | 729 | return NULL; |
| 725 | } | 730 | } |
| 726 | q = ctx->pos; | 731 | q = ctx->pos; |
| 727 | ctx->pos++; | 732 | ctx->pos++; |
| 728 | if (ctx->pos >= ctx->end) { | 733 | if (ctx->pos >= ctx->end) { |
| 729 | PLIST_XML_ERR("EOF while parsing '%s'\n", p); | 734 | PLIST_XML_ERR("EOF while parsing '%s'\n", p); |
| 730 | ctx->err++; | 735 | ctx->err = PLIST_ERR_PARSE; |
| 731 | return NULL; | 736 | return NULL; |
| 732 | } | 737 | } |
| 733 | if (*ctx->pos == '!') { | 738 | if (*ctx->pos == '!') { |
| 734 | ctx->pos++; | 739 | ctx->pos++; |
| 735 | if (ctx->pos >= ctx->end-1) { | 740 | if (ctx->pos >= ctx->end-1) { |
| 736 | PLIST_XML_ERR("EOF while parsing <! special tag\n"); | 741 | PLIST_XML_ERR("EOF while parsing <! special tag\n"); |
| 737 | ctx->err++; | 742 | ctx->err = PLIST_ERR_PARSE; |
| 738 | return NULL; | 743 | return NULL; |
| 739 | } | 744 | } |
| 740 | if (*ctx->pos == '-' && *(ctx->pos+1) == '-') { | 745 | if (*ctx->pos == '-' && *(ctx->pos+1) == '-') { |
| @@ -747,7 +752,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 747 | find_str(ctx, "-->", 3, 0); | 752 | find_str(ctx, "-->", 3, 0); |
| 748 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { | 753 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { |
| 749 | PLIST_XML_ERR("EOF while looking for end of comment\n"); | 754 | PLIST_XML_ERR("EOF while looking for end of comment\n"); |
| 750 | ctx->err++; | 755 | ctx->err = PLIST_ERR_PARSE; |
| 751 | return NULL; | 756 | return NULL; |
| 752 | } | 757 | } |
| 753 | ctx->pos += 3; | 758 | ctx->pos += 3; |
| @@ -755,7 +760,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 755 | ctx->pos++; | 760 | ctx->pos++; |
| 756 | if (ctx->pos >= ctx->end - 8) { | 761 | if (ctx->pos >= ctx->end - 8) { |
| 757 | PLIST_XML_ERR("EOF while parsing <[ tag\n"); | 762 | PLIST_XML_ERR("EOF while parsing <[ tag\n"); |
| 758 | ctx->err++; | 763 | ctx->err = PLIST_ERR_PARSE; |
| 759 | return NULL; | 764 | return NULL; |
| 760 | } | 765 | } |
| 761 | if (strncmp(ctx->pos, "CDATA[", 6) == 0) { | 766 | if (strncmp(ctx->pos, "CDATA[", 6) == 0) { |
| @@ -771,7 +776,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 771 | find_str(ctx, "]]>", 3, 0); | 776 | find_str(ctx, "]]>", 3, 0); |
| 772 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "]]>", 3) != 0) { | 777 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "]]>", 3) != 0) { |
| 773 | PLIST_XML_ERR("EOF while looking for end of CDATA block\n"); | 778 | PLIST_XML_ERR("EOF while looking for end of CDATA block\n"); |
| 774 | ctx->err++; | 779 | ctx->err = PLIST_ERR_PARSE; |
| 775 | return NULL; | 780 | return NULL; |
| 776 | } | 781 | } |
| 777 | q = ctx->pos; | 782 | q = ctx->pos; |
| @@ -785,14 +790,14 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 785 | p = ctx->pos; | 790 | p = ctx->pos; |
| 786 | find_next(ctx, " \r\n\t>", 5, 1); | 791 | find_next(ctx, " \r\n\t>", 5, 1); |
| 787 | PLIST_XML_ERR("Invalid special tag <[%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); | 792 | PLIST_XML_ERR("Invalid special tag <[%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); |
| 788 | ctx->err++; | 793 | ctx->err = PLIST_ERR_PARSE; |
| 789 | return NULL; | 794 | return NULL; |
| 790 | } | 795 | } |
| 791 | } else { | 796 | } else { |
| 792 | p = ctx->pos; | 797 | p = ctx->pos; |
| 793 | find_next(ctx, " \r\n\t>", 5, 1); | 798 | find_next(ctx, " \r\n\t>", 5, 1); |
| 794 | PLIST_XML_ERR("Invalid special tag <!%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); | 799 | PLIST_XML_ERR("Invalid special tag <!%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); |
| 795 | ctx->err++; | 800 | ctx->err = PLIST_ERR_PARSE; |
| 796 | return NULL; | 801 | return NULL; |
| 797 | } | 802 | } |
| 798 | } else if (*ctx->pos == '/') { | 803 | } else if (*ctx->pos == '/') { |
| @@ -801,25 +806,25 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le | |||
| 801 | p = ctx->pos; | 806 | p = ctx->pos; |
| 802 | find_next(ctx, " \r\n\t>", 5, 1); | 807 | find_next(ctx, " \r\n\t>", 5, 1); |
| 803 | PLIST_XML_ERR("Invalid tag <%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); | 808 | PLIST_XML_ERR("Invalid tag <%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); |
| 804 | ctx->err++; | 809 | ctx->err = PLIST_ERR_PARSE; |
| 805 | return NULL; | 810 | return NULL; |
| 806 | } | 811 | } |
| 807 | } while (1); | 812 | } while (1); |
| 808 | ctx->pos++; | 813 | ctx->pos++; |
| 809 | if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) { | 814 | if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) { |
| 810 | PLIST_XML_ERR("EOF or end tag mismatch\n"); | 815 | PLIST_XML_ERR("EOF or end tag mismatch\n"); |
| 811 | ctx->err++; | 816 | ctx->err = PLIST_ERR_PARSE; |
| 812 | return NULL; | 817 | return NULL; |
| 813 | } | 818 | } |
| 814 | ctx->pos+=tag_len; | 819 | ctx->pos+=tag_len; |
| 815 | parse_skip_ws(ctx); | 820 | parse_skip_ws(ctx); |
| 816 | if (ctx->pos >= ctx->end) { | 821 | if (ctx->pos >= ctx->end) { |
| 817 | PLIST_XML_ERR("EOF while parsing closing tag\n"); | 822 | PLIST_XML_ERR("EOF while parsing closing tag\n"); |
| 818 | ctx->err++; | 823 | ctx->err = PLIST_ERR_PARSE; |
| 819 | return NULL; | 824 | return NULL; |
| 820 | } else if (*ctx->pos != '>') { | 825 | } else if (*ctx->pos != '>') { |
| 821 | PLIST_XML_ERR("Invalid closing tag; expected '>', found '%c'\n", *ctx->pos); | 826 | PLIST_XML_ERR("Invalid closing tag; expected '>', found '%c'\n", *ctx->pos); |
| 822 | ctx->err++; | 827 | ctx->err = PLIST_ERR_PARSE; |
| 823 | return NULL; | 828 | return NULL; |
| 824 | } | 829 | } |
| 825 | ctx->pos++; | 830 | ctx->pos++; |
| @@ -995,6 +1000,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 995 | void *prev; | 1000 | void *prev; |
| 996 | }; | 1001 | }; |
| 997 | struct node_path_item* node_path = NULL; | 1002 | struct node_path_item* node_path = NULL; |
| 1003 | int depth = 0; | ||
| 998 | 1004 | ||
| 999 | while (ctx->pos < ctx->end && !ctx->err) { | 1005 | while (ctx->pos < ctx->end && !ctx->err) { |
| 1000 | parse_skip_ws(ctx); | 1006 | parse_skip_ws(ctx); |
| @@ -1005,13 +1011,13 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1005 | p = ctx->pos; | 1011 | p = ctx->pos; |
| 1006 | find_next(ctx, " \t\r\n", 4, 0); | 1012 | find_next(ctx, " \t\r\n", 4, 0); |
| 1007 | PLIST_XML_ERR("Expected: opening tag, found: %.*s\n", (int)(ctx->pos - p), p); | 1013 | PLIST_XML_ERR("Expected: opening tag, found: %.*s\n", (int)(ctx->pos - p), p); |
| 1008 | ctx->err++; | 1014 | ctx->err = PLIST_ERR_PARSE; |
| 1009 | goto err_out; | 1015 | goto err_out; |
| 1010 | } | 1016 | } |
| 1011 | ctx->pos++; | 1017 | ctx->pos++; |
| 1012 | if (ctx->pos >= ctx->end) { | 1018 | if (ctx->pos >= ctx->end) { |
| 1013 | PLIST_XML_ERR("EOF while parsing tag\n"); | 1019 | PLIST_XML_ERR("EOF while parsing tag\n"); |
| 1014 | ctx->err++; | 1020 | ctx->err = PLIST_ERR_PARSE; |
| 1015 | goto err_out; | 1021 | goto err_out; |
| 1016 | } | 1022 | } |
| 1017 | 1023 | ||
| @@ -1019,12 +1025,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1019 | find_str(ctx, "?>", 2, 1); | 1025 | find_str(ctx, "?>", 2, 1); |
| 1020 | if (ctx->pos > ctx->end-2) { | 1026 | if (ctx->pos > ctx->end-2) { |
| 1021 | PLIST_XML_ERR("EOF while looking for <? tag closing marker\n"); | 1027 | PLIST_XML_ERR("EOF while looking for <? tag closing marker\n"); |
| 1022 | ctx->err++; | 1028 | ctx->err = PLIST_ERR_PARSE; |
| 1023 | goto err_out; | 1029 | goto err_out; |
| 1024 | } | 1030 | } |
| 1025 | if (strncmp(ctx->pos, "?>", 2) != 0) { | 1031 | if (strncmp(ctx->pos, "?>", 2) != 0) { |
| 1026 | PLIST_XML_ERR("Couldn't find <? tag closing marker\n"); | 1032 | PLIST_XML_ERR("Couldn't find <? tag closing marker\n"); |
| 1027 | ctx->err++; | 1033 | ctx->err = PLIST_ERR_PARSE; |
| 1028 | goto err_out; | 1034 | goto err_out; |
| 1029 | } | 1035 | } |
| 1030 | ctx->pos += 2; | 1036 | ctx->pos += 2; |
| @@ -1036,7 +1042,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1036 | find_str(ctx,"-->", 3, 0); | 1042 | find_str(ctx,"-->", 3, 0); |
| 1037 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { | 1043 | if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { |
| 1038 | PLIST_XML_ERR("Couldn't find end of comment\n"); | 1044 | PLIST_XML_ERR("Couldn't find end of comment\n"); |
| 1039 | ctx->err++; | 1045 | ctx->err = PLIST_ERR_PARSE; |
| 1040 | goto err_out; | 1046 | goto err_out; |
| 1041 | } | 1047 | } |
| 1042 | ctx->pos+=3; | 1048 | ctx->pos+=3; |
| @@ -1047,7 +1053,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1047 | find_next(ctx, " \t\r\n[>", 6, 1); | 1053 | find_next(ctx, " \t\r\n[>", 6, 1); |
| 1048 | if (ctx->pos >= ctx->end) { | 1054 | if (ctx->pos >= ctx->end) { |
| 1049 | PLIST_XML_ERR("EOF while parsing !DOCTYPE\n"); | 1055 | PLIST_XML_ERR("EOF while parsing !DOCTYPE\n"); |
| 1050 | ctx->err++; | 1056 | ctx->err = PLIST_ERR_PARSE; |
| 1051 | goto err_out; | 1057 | goto err_out; |
| 1052 | } | 1058 | } |
| 1053 | if (*ctx->pos == '[') { | 1059 | if (*ctx->pos == '[') { |
| @@ -1065,7 +1071,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1065 | find_str(ctx, "]>", 2, 1); | 1071 | find_str(ctx, "]>", 2, 1); |
| 1066 | if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) { | 1072 | if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) { |
| 1067 | PLIST_XML_ERR("Couldn't find end of DOCTYPE\n"); | 1073 | PLIST_XML_ERR("Couldn't find end of DOCTYPE\n"); |
| 1068 | ctx->err++; | 1074 | ctx->err = PLIST_ERR_PARSE; |
| 1069 | goto err_out; | 1075 | goto err_out; |
| 1070 | } | 1076 | } |
| 1071 | ctx->pos += 2; | 1077 | ctx->pos += 2; |
| @@ -1074,7 +1080,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1074 | p = ctx->pos; | 1080 | p = ctx->pos; |
| 1075 | find_next(ctx, " \r\n\t>", 5, 1); | 1081 | find_next(ctx, " \r\n\t>", 5, 1); |
| 1076 | PLIST_XML_ERR("Invalid or incomplete special tag <%.*s> encountered\n", (int)(ctx->pos - p), p); | 1082 | PLIST_XML_ERR("Invalid or incomplete special tag <%.*s> encountered\n", (int)(ctx->pos - p), p); |
| 1077 | ctx->err++; | 1083 | ctx->err = PLIST_ERR_PARSE; |
| 1078 | goto err_out; | 1084 | goto err_out; |
| 1079 | } | 1085 | } |
| 1080 | continue; | 1086 | continue; |
| @@ -1085,7 +1091,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1085 | find_next(ctx," \r\n\t<>", 6, 0); | 1091 | find_next(ctx," \r\n\t<>", 6, 0); |
| 1086 | if (ctx->pos >= ctx->end) { | 1092 | if (ctx->pos >= ctx->end) { |
| 1087 | PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); | 1093 | PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); |
| 1088 | ctx->err++; | 1094 | ctx->err = PLIST_ERR_PARSE; |
| 1089 | goto err_out; | 1095 | goto err_out; |
| 1090 | } | 1096 | } |
| 1091 | size_t taglen = ctx->pos - p; | 1097 | size_t taglen = ctx->pos - p; |
| @@ -1097,12 +1103,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1097 | } | 1103 | } |
| 1098 | if (ctx->pos >= ctx->end) { | 1104 | if (ctx->pos >= ctx->end) { |
| 1099 | PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); | 1105 | PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); |
| 1100 | ctx->err++; | 1106 | ctx->err = PLIST_ERR_PARSE; |
| 1101 | goto err_out; | 1107 | goto err_out; |
| 1102 | } | 1108 | } |
| 1103 | if (*ctx->pos != '>') { | 1109 | if (*ctx->pos != '>') { |
| 1104 | PLIST_XML_ERR("Missing '>' for tag <%s\n", tag); | 1110 | PLIST_XML_ERR("Missing '>' for tag <%s\n", tag); |
| 1105 | ctx->err++; | 1111 | ctx->err = PLIST_ERR_PARSE; |
| 1106 | goto err_out; | 1112 | goto err_out; |
| 1107 | } | 1113 | } |
| 1108 | if (*(ctx->pos-1) == '/') { | 1114 | if (*(ctx->pos-1) == '/') { |
| @@ -1123,14 +1129,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1123 | } | 1129 | } |
| 1124 | if (is_empty) { | 1130 | if (is_empty) { |
| 1125 | PLIST_XML_ERR("Empty plist tag\n"); | 1131 | PLIST_XML_ERR("Empty plist tag\n"); |
| 1126 | ctx->err++; | 1132 | ctx->err = PLIST_ERR_PARSE; |
| 1127 | goto err_out; | 1133 | goto err_out; |
| 1128 | } | 1134 | } |
| 1129 | 1135 | ||
| 1130 | struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); | 1136 | struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); |
| 1131 | if (!path_item) { | 1137 | if (!path_item) { |
| 1132 | PLIST_XML_ERR("out of memory when allocating node path item\n"); | 1138 | PLIST_XML_ERR("out of memory when allocating node path item\n"); |
| 1133 | ctx->err++; | 1139 | ctx->err = PLIST_ERR_PARSE; |
| 1134 | goto err_out; | 1140 | goto err_out; |
| 1135 | } | 1141 | } |
| 1136 | path_item->type = "plist"; | 1142 | path_item->type = "plist"; |
| @@ -1141,17 +1147,17 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1141 | } else if (!strcmp(tag, "/plist")) { | 1147 | } else if (!strcmp(tag, "/plist")) { |
| 1142 | if (!has_content) { | 1148 | if (!has_content) { |
| 1143 | PLIST_XML_ERR("encountered empty plist tag\n"); | 1149 | PLIST_XML_ERR("encountered empty plist tag\n"); |
| 1144 | ctx->err++; | 1150 | ctx->err = PLIST_ERR_PARSE; |
| 1145 | goto err_out; | 1151 | goto err_out; |
| 1146 | } | 1152 | } |
| 1147 | if (!node_path) { | 1153 | if (!node_path) { |
| 1148 | PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); | 1154 | PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); |
| 1149 | ctx->err++; | 1155 | ctx->err = PLIST_ERR_PARSE; |
| 1150 | goto err_out; | 1156 | goto err_out; |
| 1151 | } | 1157 | } |
| 1152 | if (strcmp(node_path->type, tag+1) != 0) { | 1158 | if (strcmp(node_path->type, tag+1) != 0) { |
| 1153 | PLIST_XML_ERR("mismatching closing tag <%s> found for opening tag <%s>\n", tag, node_path->type); | 1159 | PLIST_XML_ERR("mismatching closing tag <%s> found for opening tag <%s>\n", tag, node_path->type); |
| 1154 | ctx->err++; | 1160 | ctx->err = PLIST_ERR_PARSE; |
| 1155 | goto err_out; | 1161 | goto err_out; |
| 1156 | } | 1162 | } |
| 1157 | struct node_path_item *path_item = node_path; | 1163 | struct node_path_item *path_item = node_path; |
| @@ -1179,7 +1185,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1179 | if (!tp) { | 1185 | if (!tp) { |
| 1180 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); | 1186 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); |
| 1181 | text_parts_free((text_part_t*)first_part.next); | 1187 | text_parts_free((text_part_t*)first_part.next); |
| 1182 | ctx->err++; | 1188 | ctx->err = PLIST_ERR_PARSE; |
| 1183 | goto err_out; | 1189 | goto err_out; |
| 1184 | } | 1190 | } |
| 1185 | if (tp->begin) { | 1191 | if (tp->begin) { |
| @@ -1188,7 +1194,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1188 | if (!str_content) { | 1194 | if (!str_content) { |
| 1189 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); | 1195 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); |
| 1190 | text_parts_free((text_part_t*)first_part.next); | 1196 | text_parts_free((text_part_t*)first_part.next); |
| 1191 | ctx->err++; | 1197 | ctx->err = PLIST_ERR_PARSE; |
| 1192 | goto err_out; | 1198 | goto err_out; |
| 1193 | } | 1199 | } |
| 1194 | char *str = str_content; | 1200 | char *str = str_content; |
| @@ -1230,7 +1236,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1230 | if (!tp) { | 1236 | if (!tp) { |
| 1231 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); | 1237 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); |
| 1232 | text_parts_free((text_part_t*)first_part.next); | 1238 | text_parts_free((text_part_t*)first_part.next); |
| 1233 | ctx->err++; | 1239 | ctx->err = PLIST_ERR_PARSE; |
| 1234 | goto err_out; | 1240 | goto err_out; |
| 1235 | } | 1241 | } |
| 1236 | if (tp->begin) { | 1242 | if (tp->begin) { |
| @@ -1239,7 +1245,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1239 | if (!str_content) { | 1245 | if (!str_content) { |
| 1240 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); | 1246 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); |
| 1241 | text_parts_free((text_part_t*)first_part.next); | 1247 | text_parts_free((text_part_t*)first_part.next); |
| 1242 | ctx->err++; | 1248 | ctx->err = PLIST_ERR_PARSE; |
| 1243 | goto err_out; | 1249 | goto err_out; |
| 1244 | } | 1250 | } |
| 1245 | data->realval = atof(str_content); | 1251 | data->realval = atof(str_content); |
| @@ -1274,14 +1280,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1274 | if (!tp) { | 1280 | if (!tp) { |
| 1275 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); | 1281 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); |
| 1276 | text_parts_free((text_part_t*)first_part.next); | 1282 | text_parts_free((text_part_t*)first_part.next); |
| 1277 | ctx->err++; | 1283 | ctx->err = PLIST_ERR_PARSE; |
| 1278 | goto err_out; | 1284 | goto err_out; |
| 1279 | } | 1285 | } |
| 1280 | str = text_parts_get_content(tp, 1, &length, NULL); | 1286 | str = text_parts_get_content(tp, 1, &length, NULL); |
| 1281 | text_parts_free((text_part_t*)first_part.next); | 1287 | text_parts_free((text_part_t*)first_part.next); |
| 1282 | if (!str) { | 1288 | if (!str) { |
| 1283 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); | 1289 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); |
| 1284 | ctx->err++; | 1290 | ctx->err = PLIST_ERR_PARSE; |
| 1285 | goto err_out; | 1291 | goto err_out; |
| 1286 | } | 1292 | } |
| 1287 | if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) { | 1293 | if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) { |
| @@ -1315,7 +1321,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1315 | if (!tp) { | 1321 | if (!tp) { |
| 1316 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); | 1322 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); |
| 1317 | text_parts_free((text_part_t*)first_part.next); | 1323 | text_parts_free((text_part_t*)first_part.next); |
| 1318 | ctx->err++; | 1324 | ctx->err = PLIST_ERR_PARSE; |
| 1319 | goto err_out; | 1325 | goto err_out; |
| 1320 | } | 1326 | } |
| 1321 | if (tp->begin) { | 1327 | if (tp->begin) { |
| @@ -1324,7 +1330,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1324 | if (!str_content) { | 1330 | if (!str_content) { |
| 1325 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); | 1331 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); |
| 1326 | text_parts_free((text_part_t*)first_part.next); | 1332 | text_parts_free((text_part_t*)first_part.next); |
| 1327 | ctx->err++; | 1333 | ctx->err = PLIST_ERR_PARSE; |
| 1328 | goto err_out; | 1334 | goto err_out; |
| 1329 | } | 1335 | } |
| 1330 | size_t size = tp->length; | 1336 | size_t size = tp->length; |
| @@ -1347,7 +1353,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1347 | if (!tp) { | 1353 | if (!tp) { |
| 1348 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); | 1354 | PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); |
| 1349 | text_parts_free((text_part_t*)first_part.next); | 1355 | text_parts_free((text_part_t*)first_part.next); |
| 1350 | ctx->err++; | 1356 | ctx->err = PLIST_ERR_PARSE; |
| 1351 | goto err_out; | 1357 | goto err_out; |
| 1352 | } | 1358 | } |
| 1353 | Time64_T timev = 0; | 1359 | Time64_T timev = 0; |
| @@ -1358,7 +1364,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1358 | if (!str_content) { | 1364 | if (!str_content) { |
| 1359 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); | 1365 | PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); |
| 1360 | text_parts_free((text_part_t*)first_part.next); | 1366 | text_parts_free((text_part_t*)first_part.next); |
| 1361 | ctx->err++; | 1367 | ctx->err = PLIST_ERR_PARSE; |
| 1362 | goto err_out; | 1368 | goto err_out; |
| 1363 | } | 1369 | } |
| 1364 | 1370 | ||
| @@ -1387,7 +1393,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1387 | } else { | 1393 | } else { |
| 1388 | PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : ""); | 1394 | PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : ""); |
| 1389 | ctx->pos = ctx->end; | 1395 | ctx->pos = ctx->end; |
| 1390 | ctx->err++; | 1396 | ctx->err = PLIST_ERR_PARSE; |
| 1391 | goto err_out; | 1397 | goto err_out; |
| 1392 | } | 1398 | } |
| 1393 | if (subnode && !closing_tag) { | 1399 | if (subnode && !closing_tag) { |
| @@ -1405,7 +1411,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1405 | case PLIST_DICT: | 1411 | case PLIST_DICT: |
| 1406 | if (!keyname) { | 1412 | if (!keyname) { |
| 1407 | PLIST_XML_ERR("missing key name while adding dict item\n"); | 1413 | PLIST_XML_ERR("missing key name while adding dict item\n"); |
| 1408 | ctx->err++; | 1414 | ctx->err = PLIST_ERR_PARSE; |
| 1409 | goto err_out; | 1415 | goto err_out; |
| 1410 | } | 1416 | } |
| 1411 | plist_dict_set_item(parent, keyname, subnode); | 1417 | plist_dict_set_item(parent, keyname, subnode); |
| @@ -1416,35 +1422,42 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1416 | default: | 1422 | default: |
| 1417 | /* should not happen */ | 1423 | /* should not happen */ |
| 1418 | PLIST_XML_ERR("parent is not a structured node\n"); | 1424 | PLIST_XML_ERR("parent is not a structured node\n"); |
| 1419 | ctx->err++; | 1425 | ctx->err = PLIST_ERR_PARSE; |
| 1420 | goto err_out; | 1426 | goto err_out; |
| 1421 | } | 1427 | } |
| 1422 | } | 1428 | } |
| 1423 | if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) { | 1429 | if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) { |
| 1430 | if (depth >= PLIST_MAX_NESTING_DEPTH) { | ||
| 1431 | PLIST_XML_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH); | ||
| 1432 | ctx->err = PLIST_ERR_MAX_NESTING; | ||
| 1433 | goto err_out; | ||
| 1434 | } | ||
| 1424 | struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); | 1435 | struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); |
| 1425 | if (!path_item) { | 1436 | if (!path_item) { |
| 1426 | PLIST_XML_ERR("out of memory when allocating node path item\n"); | 1437 | PLIST_XML_ERR("out of memory when allocating node path item\n"); |
| 1427 | ctx->err++; | 1438 | ctx->err = PLIST_ERR_PARSE; |
| 1428 | goto err_out; | 1439 | goto err_out; |
| 1429 | } | 1440 | } |
| 1430 | path_item->type = (data->type == PLIST_DICT) ? XPLIST_DICT : XPLIST_ARRAY; | 1441 | path_item->type = (data->type == PLIST_DICT) ? XPLIST_DICT : XPLIST_ARRAY; |
| 1431 | path_item->prev = node_path; | 1442 | path_item->prev = node_path; |
| 1432 | node_path = path_item; | 1443 | node_path = path_item; |
| 1433 | 1444 | ||
| 1445 | depth++; | ||
| 1434 | parent = subnode; | 1446 | parent = subnode; |
| 1435 | } | 1447 | } |
| 1436 | subnode = NULL; | 1448 | subnode = NULL; |
| 1437 | } else if (closing_tag) { | 1449 | } else if (closing_tag) { |
| 1438 | if (!node_path) { | 1450 | if (!node_path) { |
| 1439 | PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); | 1451 | PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); |
| 1440 | ctx->err++; | 1452 | ctx->err = PLIST_ERR_PARSE; |
| 1441 | goto err_out; | 1453 | goto err_out; |
| 1442 | } | 1454 | } |
| 1443 | if (strcmp(node_path->type, tag+1) != 0) { | 1455 | if (strcmp(node_path->type, tag+1) != 0) { |
| 1444 | PLIST_XML_ERR("unexpected %s found (for opening %s)\n", tag, node_path->type); | 1456 | PLIST_XML_ERR("unexpected %s found (for opening %s)\n", tag, node_path->type); |
| 1445 | ctx->err++; | 1457 | ctx->err = PLIST_ERR_PARSE; |
| 1446 | goto err_out; | 1458 | goto err_out; |
| 1447 | } | 1459 | } |
| 1460 | if (depth > 0) depth--; | ||
| 1448 | struct node_path_item *path_item = node_path; | 1461 | struct node_path_item *path_item = node_path; |
| 1449 | node_path = (struct node_path_item*)node_path->prev; | 1462 | node_path = (struct node_path_item*)node_path->prev; |
| 1450 | free(path_item); | 1463 | free(path_item); |
| @@ -1466,7 +1479,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) | |||
| 1466 | 1479 | ||
| 1467 | if (node_path) { | 1480 | if (node_path) { |
| 1468 | PLIST_XML_ERR("EOF encountered while </%s> was expected\n", node_path->type); | 1481 | PLIST_XML_ERR("EOF encountered while </%s> was expected\n", node_path->type); |
| 1469 | ctx->err++; | 1482 | ctx->err = PLIST_ERR_PARSE; |
| 1470 | } | 1483 | } |
| 1471 | 1484 | ||
| 1472 | err_out: | 1485 | err_out: |
| @@ -1481,10 +1494,10 @@ err_out: | |||
| 1481 | free(path_item); | 1494 | free(path_item); |
| 1482 | } | 1495 | } |
| 1483 | 1496 | ||
| 1484 | if (ctx->err) { | 1497 | if (ctx->err != PLIST_ERR_SUCCESS) { |
| 1485 | plist_free(*plist); | 1498 | plist_free(*plist); |
| 1486 | *plist = NULL; | 1499 | *plist = NULL; |
| 1487 | return PLIST_ERR_PARSE; | 1500 | return ctx->err; |
| 1488 | } | 1501 | } |
| 1489 | 1502 | ||
| 1490 | /* check if we have a UID "dict" so we can replace it with a proper UID node */ | 1503 | /* check if we have a UID "dict" so we can replace it with a proper UID node */ |
| @@ -1511,7 +1524,7 @@ plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * pli | |||
| 1511 | return PLIST_ERR_INVALID_ARG; | 1524 | return PLIST_ERR_INVALID_ARG; |
| 1512 | } | 1525 | } |
| 1513 | 1526 | ||
| 1514 | struct _parse_ctx ctx = { plist_xml, plist_xml + length, 0 }; | 1527 | struct _parse_ctx ctx = { plist_xml, plist_xml + length, PLIST_ERR_SUCCESS }; |
| 1515 | 1528 | ||
| 1516 | return node_from_xml(&ctx, plist); | 1529 | return node_from_xml(&ctx, plist); |
| 1517 | } | 1530 | } |
