CVE-2017-6436: Improper Input Validation (CWE-20)
value: The parse_string_node function in bplist.c in libimobiledevice libplist 1.12 allows local users to cause a denial of service (memory allocation error) via a crafted plist file.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 5
Published: 2017-03-15T14:59Z
Repository: https://github.com/libimobiledevice/libplist
Language: C
Files changed: src/bplist.c
Commit date: 2017-02-10 13:42:46 +0100
Commit message: bplist: Fix data range check for string/data/dict/array nodes

Passing a size of 0xFFFFFFFFFFFFFFFF to parse_string_node() might result
in a memcpy with a size of -1, leading to undefined behavior.
This commit makes sure that the actual node data (which depends on the size)
is in the range start_of_object..start_of_object+size.

Credit to OSS-Fuzz

Diff: diff --git a/src/bplist.c b/src/bplist.c
index 0fd149e..7d21b27 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -652,37 +652,37 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
             return NULL;
         }
         return parse_date_node(object, size);
 
     case BPLIST_DATA:
-        if (*object + size > bplist->offset_table) {
+        if (*object + size < *object || *object + size > bplist->offset_table) {
             PLIST_BIN_ERR("%s: BPLIST_DATA data bytes point outside of valid range\n", __func__);
             return NULL;
         }
         return parse_data_node(object, size);
 
     case BPLIST_STRING:
-        if (*object + size > bplist->offset_table) {
+        if (*object + size < *object || *object + size > bplist->offset_table) {
             PLIST_BIN_ERR("%s: BPLIST_STRING data bytes point outside of valid range\n", __func__);
             return NULL;
         }
         return parse_string_node(object, size);
 
     case BPLIST_UNICODE:
         if (size*2 < size) {
             PLIST_BIN_ERR("%s: Integer overflow when calculating BPLIST_UNICODE data size.\n", __func__);
             return NULL;
         }
-        if (*object + size*2 > bplist->offset_table) {
+        if (*object + size*2 < *object || *object + size*2 > bplist->offset_table) {
             PLIST_BIN_ERR("%s: BPLIST_UNICODE data bytes point outside of valid range\n", __func__);
             return NULL;
         }
         return parse_unicode_node(object, size);
 
     case BPLIST_SET:
     case BPLIST_ARRAY:
-        if (*object + size > bplist->offset_table) {
+        if (*object + size < *object || *object + size > bplist->offset_table) {
             PLIST_BIN_ERR("%s: BPLIST_ARRAY data bytes point outside of valid range\n", __func__);
             return NULL;
         }
         return parse_array_node(bplist, object, size);
 
@@ -692,12 +692,12 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
             return NULL;
         }
         return parse_uid_node(object, size);
 
     case BPLIST_DICT:
-        if (*object + size > bplist->offset_table) {
-            PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__);
+        if (*object + size < *object || *object + size > bplist->offset_table) {
+            PLIST_BIN_ERR("%s: BPLIST_DICT data bytes point outside of valid range\n", __func__);
             return NULL;
         }
         return parse_dict_node(bplist, object, size);
 
     default:

Vulnerable code:         if (*object + size > bplist->offset_table) {
        if (*object + size > bplist->offset_table) {
        if (*object + size*2 > bplist->offset_table) {
        if (*object + size > bplist->offset_table) {
        if (*object + size > bplist->offset_table) {
            PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__);
Fixed code:         if (*object + size < *object || *object + size > bplist->offset_table) {
        if (*object + size < *object || *object + size > bplist->offset_table) {
        if (*object + size*2 < *object || *object + size*2 > bplist->offset_table) {
        if (*object + size < *object || *object + size > bplist->offset_table) {
        if (*object + size < *object || *object + size > bplist->offset_table) {
            PLIST_BIN_ERR("%s: BPLIST_DICT data bytes point outside of valid range\n", __func__);