summaryrefslogtreecommitdiffstats
path: root/src/oplist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-01-17 15:18:06 +0100
committerGravatar Nikias Bassen2026-01-17 16:04:00 +0100
commite45099fb21b679aa0cdb0db394587bb5ba675b0c (patch)
treeb1a2c1dd34877d83a04d6d6fab804fb2e5a65f2d /src/oplist.c
parent26dd27c435a0d110c924e1fef34ad0f6ae60e251 (diff)
downloadlibplist-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.
Diffstat (limited to 'src/oplist.c')
-rw-r--r--src/oplist.c69
1 files changed, 37 insertions, 32 deletions
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};
517typedef struct _parse_ctx* parse_ctx; 522typedef 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
911err_out: 916err_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}