summaryrefslogtreecommitdiffstats
path: root/src/jplist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2022-01-31 02:55:18 +0100
committerGravatar Nikias Bassen2022-01-31 02:55:18 +0100
commit924ba961d68f6833f617fd3ad03c40f63f287142 (patch)
tree140dd874ce171810c9fcc5cb98c3a071445aa717 /src/jplist.c
parent25f2f01c2693da8cc651d80debda9ad61fa17743 (diff)
downloadlibplist-924ba961d68f6833f617fd3ad03c40f63f287142.tar.gz
libplist-924ba961d68f6833f617fd3ad03c40f63f287142.tar.bz2
jplist: Fix OOB read by making sure the JSMN token index is in valid range
Credit to OSS-Fuzz
Diffstat (limited to 'src/jplist.c')
-rw-r--r--src/jplist.c79
1 files changed, 48 insertions, 31 deletions
diff --git a/src/jplist.c b/src/jplist.c
index 88cce28..2182079 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -418,16 +418,21 @@ PLIST_API int plist_to_json(plist_t plist, char **json, uint32_t* length, int pr
418 return PLIST_ERR_SUCCESS; 418 return PLIST_ERR_SUCCESS;
419} 419}
420 420
421static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index) 421typedef struct {
422 jsmntok_t* tokens;
423 int count;
424} jsmntok_info_t;
425
426static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index)
422{ 427{
423 if (tokens[*index].type != JSMN_PRIMITIVE) { 428 if (ti->tokens[*index].type != JSMN_PRIMITIVE) {
424 PLIST_JSON_ERR("%s: token type != JSMN_PRIMITIVE\n", __func__); 429 PLIST_JSON_ERR("%s: token type != JSMN_PRIMITIVE\n", __func__);
425 return NULL; 430 return NULL;
426 } 431 }
427 plist_t val = NULL; 432 plist_t val = NULL;
428 const char* str_val = js + tokens[*index].start; 433 const char* str_val = js + ti->tokens[*index].start;
429 const char* str_end = js + tokens[*index].end; 434 const char* str_end = js + ti->tokens[*index].end;
430 size_t str_len = tokens[*index].end - tokens[*index].start; 435 size_t str_len = ti->tokens[*index].end - ti->tokens[*index].start;
431 if (!strncmp("false", str_val, str_len)) { 436 if (!strncmp("false", str_val, str_len)) {
432 val = plist_new_bool(0); 437 val = plist_new_bool(0);
433 } else if (!strncmp("true", str_val, str_len)) { 438 } else if (!strncmp("true", str_val, str_len)) {
@@ -540,15 +545,15 @@ static char* unescape_string(const char* str_val, size_t str_len, size_t *new_le
540 return strval; 545 return strval;
541} 546}
542 547
543static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index) 548static plist_t parse_string(const char* js, jsmntok_info_t* ti, int* index)
544{ 549{
545 if (tokens[*index].type != JSMN_STRING) { 550 if (ti->tokens[*index].type != JSMN_STRING) {
546 PLIST_JSON_ERR("%s: token type != JSMN_STRING\n", __func__); 551 PLIST_JSON_ERR("%s: token type != JSMN_STRING\n", __func__);
547 return NULL; 552 return NULL;
548 } 553 }
549 554
550 size_t str_len = 0; ; 555 size_t str_len = 0; ;
551 char* strval = unescape_string(js + tokens[*index].start, tokens[*index].end - tokens[*index].start, &str_len); 556 char* strval = unescape_string(js + ti->tokens[*index].start, ti->tokens[*index].end - ti->tokens[*index].start, &str_len);
552 if (!strval) { 557 if (!strval) {
553 return NULL; 558 return NULL;
554 } 559 }
@@ -564,32 +569,36 @@ static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index)
564 return node; 569 return node;
565} 570}
566 571
567static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index); 572static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index);
568 573
569static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index) 574static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
570{ 575{
571 if (tokens[*index].type != JSMN_ARRAY) { 576 if (ti->tokens[*index].type != JSMN_ARRAY) {
572 PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__); 577 PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__);
573 return NULL; 578 return NULL;
574 } 579 }
575 plist_t arr = plist_new_array(); 580 plist_t arr = plist_new_array();
576 int num_tokens = tokens[*index].size; 581 int num_tokens = ti->tokens[*index].size;
577 int num; 582 int num;
578 int j = (*index)+1; 583 int j = (*index)+1;
579 for (num = 0; num < num_tokens; num++) { 584 for (num = 0; num < num_tokens; num++) {
585 if (j >= ti->count) {
586 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
587 return NULL;
588 }
580 plist_t val = NULL; 589 plist_t val = NULL;
581 switch (tokens[j].type) { 590 switch (ti->tokens[j].type) {
582 case JSMN_OBJECT: 591 case JSMN_OBJECT:
583 val = parse_object(js, tokens, &j); 592 val = parse_object(js, ti, &j);
584 break; 593 break;
585 case JSMN_ARRAY: 594 case JSMN_ARRAY:
586 val = parse_array(js, tokens, &j); 595 val = parse_array(js, ti, &j);
587 break; 596 break;
588 case JSMN_STRING: 597 case JSMN_STRING:
589 val = parse_string(js, tokens, &j); 598 val = parse_string(js, ti, &j);
590 break; 599 break;
591 case JSMN_PRIMITIVE: 600 case JSMN_PRIMITIVE:
592 val = parse_primitive(js, tokens, &j); 601 val = parse_primitive(js, ti, &j);
593 break; 602 break;
594 default: 603 default:
595 break; 604 break;
@@ -605,19 +614,23 @@ static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index)
605 return arr; 614 return arr;
606} 615}
607 616
608static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index) 617static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
609{ 618{
610 if (tokens[*index].type != JSMN_OBJECT) { 619 if (ti->tokens[*index].type != JSMN_OBJECT) {
611 PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__); 620 PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__);
612 return NULL; 621 return NULL;
613 } 622 }
614 plist_t obj = plist_new_dict(); 623 plist_t obj = plist_new_dict();
615 int num_tokens = tokens[*index].size; 624 int num_tokens = ti->tokens[*index].size;
616 int num; 625 int num;
617 int j = (*index)+1; 626 int j = (*index)+1;
618 for (num = 0; num < num_tokens; num++) { 627 for (num = 0; num < num_tokens; num++) {
619 if (tokens[j].type == JSMN_STRING) { 628 if (j >= ti->count) {
620 char* key = unescape_string(js + tokens[j].start, tokens[j].end - tokens[j].start, NULL); 629 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
630 return NULL;
631 }
632 if (ti->tokens[j].type == JSMN_STRING) {
633 char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL);
621 if (!key) { 634 if (!key) {
622 plist_free(obj); 635 plist_free(obj);
623 return NULL; 636 return NULL;
@@ -625,24 +638,27 @@ static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index)
625 plist_t val = NULL; 638 plist_t val = NULL;
626 j++; 639 j++;
627 num++; 640 num++;
628 switch (tokens[j].type) { 641 switch (ti->tokens[j].type) {
629 case JSMN_OBJECT: 642 case JSMN_OBJECT:
630 val = parse_object(js, tokens, &j); 643 val = parse_object(js, ti, &j);
631 break; 644 break;
632 case JSMN_ARRAY: 645 case JSMN_ARRAY:
633 val = parse_array(js, tokens, &j); 646 val = parse_array(js, ti, &j);
634 break; 647 break;
635 case JSMN_STRING: 648 case JSMN_STRING:
636 val = parse_string(js, tokens, &j); 649 val = parse_string(js, ti, &j);
637 break; 650 break;
638 case JSMN_PRIMITIVE: 651 case JSMN_PRIMITIVE:
639 val = parse_primitive(js, tokens, &j); 652 val = parse_primitive(js, ti, &j);
640 break; 653 break;
641 default: 654 default:
642 break; 655 break;
643 } 656 }
644 if (val) { 657 if (val) {
645 plist_dict_set_item(obj, key, val); 658 plist_dict_set_item(obj, key, val);
659 } else {
660 plist_free(obj);
661 return NULL;
646 } 662 }
647 free(key); 663 free(key);
648 } else { 664 } else {
@@ -707,18 +723,19 @@ PLIST_API int plist_from_json(const char *json, uint32_t length, plist_t * plist
707 } 723 }
708 724
709 int startindex = 0; 725 int startindex = 0;
726 jsmntok_info_t ti = { tokens, parser.toknext };
710 switch (tokens[startindex].type) { 727 switch (tokens[startindex].type) {
711 case JSMN_PRIMITIVE: 728 case JSMN_PRIMITIVE:
712 *plist = parse_primitive(json, tokens, &startindex); 729 *plist = parse_primitive(json, &ti, &startindex);
713 break; 730 break;
714 case JSMN_STRING: 731 case JSMN_STRING:
715 *plist = parse_string(json, tokens, &startindex); 732 *plist = parse_string(json, &ti, &startindex);
716 break; 733 break;
717 case JSMN_ARRAY: 734 case JSMN_ARRAY:
718 *plist = parse_array(json, tokens, &startindex); 735 *plist = parse_array(json, &ti, &startindex);
719 break; 736 break;
720 case JSMN_OBJECT: 737 case JSMN_OBJECT:
721 *plist = parse_object(json, tokens, &startindex); 738 *plist = parse_object(json, &ti, &startindex);
722 break; 739 break;
723 default: 740 default:
724 break; 741 break;