summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2017-02-05 06:01:11 +0100
committerGravatar Nikias Bassen2017-02-05 06:01:11 +0100
commit31d7cc5370f37cc6b9ecc4e26256e74634554343 (patch)
tree85d35012ca641e012c1d9c8acd2fd76c5dfb81a8 /src
parent67eb54ab73f07560ae72058ed6ab6b47936be695 (diff)
downloadlibplist-31d7cc5370f37cc6b9ecc4e26256e74634554343.tar.gz
libplist-31d7cc5370f37cc6b9ecc4e26256e74634554343.tar.bz2
bplist: Add error/debug logging (only if configured with --enable-debug)
This commit adds proper debug/error messages being printed if the binary plist parser encounters anything abnormal. To enable debug logging, libplist must be configured with --enable-debug, and the environment variable PLIST_BIN_DEBUG must be set to "1".
Diffstat (limited to 'src')
-rw-r--r--src/bplist.c143
-rw-r--r--src/plist.c4
2 files changed, 116 insertions, 31 deletions
diff --git a/src/bplist.c b/src/bplist.c
index 474025b..73202ff 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -2,7 +2,7 @@
2 * bplist.c 2 * bplist.c
3 * Binary plist implementation 3 * Binary plist implementation
4 * 4 *
5 * Copyright (c) 2011-2016 Nikias Bassen, All Rights Reserved. 5 * Copyright (c) 2011-2017 Nikias Bassen, All Rights Reserved.
6 * Copyright (c) 2008-2010 Jonathan Beck, All Rights Reserved. 6 * Copyright (c) 2008-2010 Jonathan Beck, All Rights Reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
@@ -190,6 +190,29 @@ struct bplist_data {
190 plist_t used_indexes; 190 plist_t used_indexes;
191}; 191};
192 192
193#ifdef DEBUG
194static int plist_bin_debug = 0;
195#define PLIST_BIN_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binparser] ERROR: " __VA_ARGS__); }
196#else
197#define PLIST_BIN_ERR(...)
198#endif
199
200void plist_bin_init(void)
201{
202 /* init binary plist stuff */
203#ifdef DEBUG
204 char *env_debug = getenv("PLIST_BIN_DEBUG");
205 if (env_debug && !strcmp(env_debug, "1")) {
206 plist_bin_debug = 1;
207 }
208#endif
209}
210
211void plist_bin_deinit(void)
212{
213 /* deinit binary plist stuff */
214}
215
193static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index); 216static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index);
194 217
195static plist_t parse_uint_node(const char **bnode, uint8_t size) 218static plist_t parse_uint_node(const char **bnode, uint8_t size)
@@ -210,6 +233,7 @@ static plist_t parse_uint_node(const char **bnode, uint8_t size)
210 break; 233 break;
211 default: 234 default:
212 free(data); 235 free(data);
236 PLIST_BIN_ERR("%s: Invalid byte size for integer node\n", __func__);
213 return NULL; 237 return NULL;
214 }; 238 };
215 239
@@ -239,6 +263,7 @@ static plist_t parse_real_node(const char **bnode, uint8_t size)
239 break; 263 break;
240 default: 264 default:
241 free(data); 265 free(data);
266 PLIST_BIN_ERR("%s: Invalid byte size for real node\n", __func__);
242 return NULL; 267 return NULL;
243 } 268 }
244 data->type = PLIST_REAL; 269 data->type = PLIST_REAL;
@@ -275,7 +300,7 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l
275 if (!unistr || (len <= 0)) return NULL; 300 if (!unistr || (len <= 0)) return NULL;
276 char *outbuf = (char*)malloc(4*(len+1)); 301 char *outbuf = (char*)malloc(4*(len+1));
277 int p = 0; 302 int p = 0;
278 int i = 0; 303 long i = 0;
279 304
280 uint16_t wc; 305 uint16_t wc;
281 uint32_t w; 306 uint32_t w;
@@ -391,6 +416,7 @@ static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, u
391 if ((index1_ptr < bplist->data || index1_ptr + bplist->ref_size > bplist->offset_table) || 416 if ((index1_ptr < bplist->data || index1_ptr + bplist->ref_size > bplist->offset_table) ||
392 (index2_ptr < bplist->data || index2_ptr + bplist->ref_size > bplist->offset_table)) { 417 (index2_ptr < bplist->data || index2_ptr + bplist->ref_size > bplist->offset_table)) {
393 plist_free(node); 418 plist_free(node);
419 PLIST_BIN_ERR("%s: dict entry %llu is outside of valid range\n", __func__, j);
394 return NULL; 420 return NULL;
395 } 421 }
396 422
@@ -399,10 +425,12 @@ static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, u
399 425
400 if (index1 >= bplist->num_objects) { 426 if (index1 >= bplist->num_objects) {
401 plist_free(node); 427 plist_free(node);
428 PLIST_BIN_ERR("%s: dict entry %llu key index (%llu) must be smaller than the number of objects (%llu)\n", __func__, j, index1, bplist->num_objects);
402 return NULL; 429 return NULL;
403 } 430 }
404 if (index2 >= bplist->num_objects) { 431 if (index2 >= bplist->num_objects) {
405 plist_free(node); 432 plist_free(node);
433 PLIST_BIN_ERR("%s: dict entry %llu value index (%llu) must be smaller than the number of objects (%llu)\n", __func__, j, index1, bplist->num_objects);
406 return NULL; 434 return NULL;
407 } 435 }
408 436
@@ -414,7 +442,7 @@ static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, u
414 } 442 }
415 443
416 if (plist_get_data(key)->type != PLIST_STRING) { 444 if (plist_get_data(key)->type != PLIST_STRING) {
417 fprintf(stderr, "ERROR: Malformed binary plist dict, invalid node type for key!\n"); 445 PLIST_BIN_ERR("%s: malformed binary plist dict, invalid node type for key!\n", __func__);
418 plist_free(node); 446 plist_free(node);
419 return NULL; 447 return NULL;
420 } 448 }
@@ -422,7 +450,7 @@ static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, u
422 /* enforce key type */ 450 /* enforce key type */
423 plist_get_data(key)->type = PLIST_KEY; 451 plist_get_data(key)->type = PLIST_KEY;
424 if (!plist_get_data(key)->strval) { 452 if (!plist_get_data(key)->strval) {
425 fprintf(stderr, "ERROR: Malformed binary plist dict, invalid key node encountered!\n"); 453 PLIST_BIN_ERR("%s: malformed binary plist dict, invalid key node encountered!\n", __func__);
426 plist_free(key); 454 plist_free(key);
427 plist_free(node); 455 plist_free(node);
428 return NULL; 456 return NULL;
@@ -462,6 +490,7 @@ static plist_t parse_array_node(struct bplist_data *bplist, const char** bnode,
462 490
463 if (index1_ptr < bplist->data || index1_ptr + bplist->ref_size > bplist->offset_table) { 491 if (index1_ptr < bplist->data || index1_ptr + bplist->ref_size > bplist->offset_table) {
464 plist_free(node); 492 plist_free(node);
493 PLIST_BIN_ERR("%s: array item %llu is outside of valid range\n", __func__, j);
465 return NULL; 494 return NULL;
466 } 495 }
467 496
@@ -469,6 +498,7 @@ static plist_t parse_array_node(struct bplist_data *bplist, const char** bnode,
469 498
470 if (index1 >= bplist->num_objects) { 499 if (index1 >= bplist->num_objects) {
471 plist_free(node); 500 plist_free(node);
501 PLIST_BIN_ERR("%s: array item %llu object index (%llu) must be smaller than the number of objects (%llu)\n", __func__, j, index1, bplist->num_objects);
472 return NULL; 502 return NULL;
473 } 503 }
474 504
@@ -491,6 +521,7 @@ static plist_t parse_uid_node(const char **bnode, uint8_t size)
491 size = size + 1; 521 size = size + 1;
492 data->intval = UINT_TO_HOST(*bnode, size); 522 data->intval = UINT_TO_HOST(*bnode, size);
493 if (data->intval > UINT32_MAX) { 523 if (data->intval > UINT32_MAX) {
524 PLIST_BIN_ERR("%s: value %llu too large for UID node (must be <= %u)\n", __func__, (uint64_t)data->intval, UINT32_MAX);
494 free(data); 525 free(data);
495 return NULL; 526 return NULL;
496 } 527 }
@@ -524,12 +555,16 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
524 case BPLIST_DICT: 555 case BPLIST_DICT:
525 { 556 {
526 uint16_t next_size = **object & BPLIST_FILL; 557 uint16_t next_size = **object & BPLIST_FILL;
527 if ((**object & BPLIST_MASK) != BPLIST_UINT) 558 if ((**object & BPLIST_MASK) != BPLIST_UINT) {
559 PLIST_BIN_ERR("%s: invalid size node type for node type 0x%02x: found 0x%02x, expected 0x%02x\n", __func__, type, **object & BPLIST_MASK, BPLIST_UINT);
528 return NULL; 560 return NULL;
561 }
529 (*object)++; 562 (*object)++;
530 next_size = 1 << next_size; 563 next_size = 1 << next_size;
531 if (*object + next_size > bplist->offset_table) 564 if (*object + next_size > bplist->offset_table) {
565 PLIST_BIN_ERR("%s: size node data bytes for node type 0x%02x point outside of valid range\n", __func__, type);
532 return NULL; 566 return NULL;
567 }
533 size = UINT_TO_HOST(*object, next_size); 568 size = UINT_TO_HOST(*object, next_size);
534 (*object) += next_size; 569 (*object) += next_size;
535 break; 570 break;
@@ -570,54 +605,75 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
570 } 605 }
571 606
572 case BPLIST_UINT: 607 case BPLIST_UINT:
573 if (*object + (uint64_t)(1 << size) > bplist->offset_table) 608 if (*object + (uint64_t)(1 << size) > bplist->offset_table) {
609 PLIST_BIN_ERR("%s: BPLIST_UINT data bytes point outside of valid range\n", __func__);
574 return NULL; 610 return NULL;
611 }
575 return parse_uint_node(object, size); 612 return parse_uint_node(object, size);
576 613
577 case BPLIST_REAL: 614 case BPLIST_REAL:
578 if (*object + (uint64_t)(1 << size) > bplist->offset_table) 615 if (*object + (uint64_t)(1 << size) > bplist->offset_table) {
616 PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__);
579 return NULL; 617 return NULL;
618 }
580 return parse_real_node(object, size); 619 return parse_real_node(object, size);
581 620
582 case BPLIST_DATE: 621 case BPLIST_DATE:
583 if (3 != size) 622 if (3 != size) {
623 PLIST_BIN_ERR("%s: invalid data size for BPLIST_DATE node\n", __func__);
584 return NULL; 624 return NULL;
585 if (*object + (uint64_t)(1 << size) > bplist->offset_table) 625 }
626 if (*object + (uint64_t)(1 << size) > bplist->offset_table) {
627 PLIST_BIN_ERR("%s: BPLIST_DATE data bytes point outside of valid range\n", __func__);
586 return NULL; 628 return NULL;
629 }
587 return parse_date_node(object, size); 630 return parse_date_node(object, size);
588 631
589 case BPLIST_DATA: 632 case BPLIST_DATA:
590 if (*object + size > bplist->offset_table) 633 if (*object + size > bplist->offset_table) {
634 PLIST_BIN_ERR("%s: BPLIST_DATA data bytes point outside of valid range\n", __func__);
591 return NULL; 635 return NULL;
636 }
592 return parse_data_node(object, size); 637 return parse_data_node(object, size);
593 638
594 case BPLIST_STRING: 639 case BPLIST_STRING:
595 if (*object + size > bplist->offset_table) 640 if (*object + size > bplist->offset_table) {
641 PLIST_BIN_ERR("%s: BPLIST_STRING data bytes point outside of valid range\n", __func__);
596 return NULL; 642 return NULL;
643 }
597 return parse_string_node(object, size); 644 return parse_string_node(object, size);
598 645
599 case BPLIST_UNICODE: 646 case BPLIST_UNICODE:
600 if (*object + size*2 > bplist->offset_table) 647 if (*object + size*2 > bplist->offset_table) {
648 PLIST_BIN_ERR("%s: BPLIST_UNICODE data bytes point outside of valid range\n", __func__);
601 return NULL; 649 return NULL;
650 }
602 return parse_unicode_node(object, size); 651 return parse_unicode_node(object, size);
603 652
604 case BPLIST_SET: 653 case BPLIST_SET:
605 case BPLIST_ARRAY: 654 case BPLIST_ARRAY:
606 if (*object + size > bplist->offset_table) 655 if (*object + size > bplist->offset_table) {
656 PLIST_BIN_ERR("%s: BPLIST_ARRAY data bytes point outside of valid range\n", __func__);
607 return NULL; 657 return NULL;
658 }
608 return parse_array_node(bplist, object, size); 659 return parse_array_node(bplist, object, size);
609 660
610 case BPLIST_UID: 661 case BPLIST_UID:
611 if (*object + size+1 > bplist->offset_table) 662 if (*object + size+1 > bplist->offset_table) {
663 PLIST_BIN_ERR("%s: BPLIST_UID data bytes point outside of valid range\n", __func__);
612 return NULL; 664 return NULL;
665 }
613 return parse_uid_node(object, size); 666 return parse_uid_node(object, size);
614 667
615 case BPLIST_DICT: 668 case BPLIST_DICT:
616 if (*object + size > bplist->offset_table) 669 if (*object + size > bplist->offset_table) {
670 PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__);
617 return NULL; 671 return NULL;
672 }
618 return parse_dict_node(bplist, object, size); 673 return parse_dict_node(bplist, object, size);
619 674
620 default: 675 default:
676 PLIST_BIN_ERR("%s: unexpected node type 0x%02x\n", __func__, type);
621 return NULL; 677 return NULL;
622 } 678 }
623 return NULL; 679 return NULL;
@@ -630,17 +686,22 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
630 plist_t plist = NULL; 686 plist_t plist = NULL;
631 const char* idx_ptr = NULL; 687 const char* idx_ptr = NULL;
632 688
633 if (node_index >= bplist->num_objects) 689 if (node_index >= bplist->num_objects) {
690 PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%llu)\n", node_index, bplist->num_objects);
634 return NULL; 691 return NULL;
692 }
635 693
636 idx_ptr = bplist->offset_table + node_index * bplist->offset_size; 694 idx_ptr = bplist->offset_table + node_index * bplist->offset_size;
637 if (idx_ptr < bplist->offset_table || 695 if (idx_ptr < bplist->offset_table ||
638 idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) 696 idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) {
697 PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index);
639 return NULL; 698 return NULL;
699 }
640 700
641 ptr = bplist->data + UINT_TO_HOST(idx_ptr, bplist->offset_size); 701 ptr = bplist->data + UINT_TO_HOST(idx_ptr, bplist->offset_size);
642 /* make sure the node offset is in a sane range */ 702 /* make sure the node offset is in a sane range */
643 if ((ptr < bplist->data) || (ptr >= bplist->offset_table)) { 703 if ((ptr < bplist->data) || (ptr >= bplist->offset_table)) {
704 PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index);
644 return NULL; 705 return NULL;
645 } 706 }
646 707
@@ -659,7 +720,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
659 plist_t node_i = plist_array_get_item(bplist->used_indexes, i); 720 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); 721 plist_t node_level = plist_array_get_item(bplist->used_indexes, bplist->level);
661 if (plist_compare_node_value(node_i, node_level)) { 722 if (plist_compare_node_value(node_i, node_level)) {
662 fprintf(stderr, "Recursion detected in binary plist. Aborting.\n"); 723 PLIST_BIN_ERR("recursion detected in binary plist\n");
663 return NULL; 724 return NULL;
664 } 725 }
665 } 726 }
@@ -684,14 +745,20 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
684 const char *end_data = NULL; 745 const char *end_data = NULL;
685 746
686 //first check we have enough data 747 //first check we have enough data
687 if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + sizeof(bplist_trailer_t))) 748 if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + sizeof(bplist_trailer_t))) {
749 PLIST_BIN_ERR("plist data is to small to hold a binary plist\n");
688 return; 750 return;
751 }
689 //check that plist_bin in actually a plist 752 //check that plist_bin in actually a plist
690 if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) 753 if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) {
754 PLIST_BIN_ERR("bplist magic mismatch\n");
691 return; 755 return;
756 }
692 //check for known version 757 //check for known version
693 if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) 758 if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) {
759 PLIST_BIN_ERR("unsupported binary plist version '%.2s\n", plist_bin+BPLIST_MAGIC_SIZE);
694 return; 760 return;
761 }
695 762
696 start_data = plist_bin + BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE; 763 start_data = plist_bin + BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE;
697 end_data = plist_bin + length - sizeof(bplist_trailer_t); 764 end_data = plist_bin + length - sizeof(bplist_trailer_t);
@@ -705,23 +772,35 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
705 root_object = be64toh(trailer->root_object_index); 772 root_object = be64toh(trailer->root_object_index);
706 offset_table = (char *)(plist_bin + be64toh(trailer->offset_table_offset)); 773 offset_table = (char *)(plist_bin + be64toh(trailer->offset_table_offset));
707 774
708 if (num_objects == 0) 775 if (num_objects == 0) {
776 PLIST_BIN_ERR("number of objects must be larger than 0\n");
709 return; 777 return;
778 }
710 779
711 if (offset_size == 0) 780 if (offset_size == 0) {
781 PLIST_BIN_ERR("offset size in trailer must be larger than 0\n");
712 return; 782 return;
783 }
713 784
714 if (ref_size == 0) 785 if (ref_size == 0) {
786 PLIST_BIN_ERR("object reference size in trailer must be larger than 0\n");
715 return; 787 return;
788 }
716 789
717 if (root_object >= num_objects) 790 if (root_object >= num_objects) {
791 PLIST_BIN_ERR("root object index (%llu) must be smaller than number of objects (%llu)\n", root_object, num_objects);
718 return; 792 return;
793 }
719 794
720 if (offset_table < start_data || offset_table >= end_data) 795 if (offset_table < start_data || offset_table >= end_data) {
796 PLIST_BIN_ERR("offset table offset points outside of valid range\n");
721 return; 797 return;
798 }
722 799
723 if (offset_table + num_objects * offset_size > end_data) 800 if (offset_table + num_objects * offset_size > end_data) {
801 PLIST_BIN_ERR("offset table points outside of valid range\n");
724 return; 802 return;
803 }
725 804
726 struct bplist_data bplist; 805 struct bplist_data bplist;
727 bplist.data = plist_bin; 806 bplist.data = plist_bin;
@@ -733,8 +812,10 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
733 bplist.level = 0; 812 bplist.level = 0;
734 bplist.used_indexes = plist_new_array(); 813 bplist.used_indexes = plist_new_array();
735 814
736 if (!bplist.used_indexes) 815 if (!bplist.used_indexes) {
816 PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n");
737 return; 817 return;
818 }
738 819
739 *plist = parse_bin_node_at_index(&bplist, root_object); 820 *plist = parse_bin_node_at_index(&bplist, root_object);
740 821
@@ -983,7 +1064,7 @@ static uint16_t *plist_utf8_to_utf16(char *unistr, long size, long *items_read,
983{ 1064{
984 uint16_t *outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t)); 1065 uint16_t *outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t));
985 int p = 0; 1066 int p = 0;
986 int i = 0; 1067 long i = 0;
987 1068
988 unsigned char c0; 1069 unsigned char c0;
989 unsigned char c1; 1070 unsigned char c1;
@@ -1017,7 +1098,7 @@ static uint16_t *plist_utf8_to_utf16(char *unistr, long size, long *items_read,
1017 i+=1; 1098 i+=1;
1018 } else { 1099 } else {
1019 // invalid character 1100 // invalid character
1020 fprintf(stderr, "invalid utf8 sequence in string at index %d\n", i); 1101 PLIST_BIN_ERR("%s: invalid utf8 sequence in string at index %lu\n", __func__, i);
1021 break; 1102 break;
1022 } 1103 }
1023 } 1104 }
diff --git a/src/plist.c b/src/plist.c
index 8c2866d..3314378 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -41,14 +41,18 @@
41 41
42extern void plist_xml_init(void); 42extern void plist_xml_init(void);
43extern void plist_xml_deinit(void); 43extern void plist_xml_deinit(void);
44extern void plist_bin_init(void);
45extern void plist_bin_deinit(void);
44 46
45static void internal_plist_init(void) 47static void internal_plist_init(void)
46{ 48{
49 plist_bin_init();
47 plist_xml_init(); 50 plist_xml_init();
48} 51}
49 52
50static void internal_plist_deinit(void) 53static void internal_plist_deinit(void)
51{ 54{
55 plist_bin_deinit();
52 plist_xml_deinit(); 56 plist_xml_deinit();
53} 57}
54 58