Commit dccd9290 authored by Nikias Bassen's avatar Nikias Bassen

bplist: Make sure sanity checks work on 32bit platforms

Because on 32-bit platforms 32-bit pointers and 64-bit sizes have been
used for the sanity checks of the offset table and object references,
the range checks would fail in certain interger-overflowish situations,
causing heap buffer overflows or other unwanted behavior.
Fixed by wideing the operands in question to 64-bit.
parent 71bcd3b6
...@@ -561,6 +561,8 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -561,6 +561,8 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
{ {
uint16_t type = 0; uint16_t type = 0;
uint64_t size = 0; uint64_t size = 0;
uint64_t pobject = 0;
uint64_t poffset_table = (uint64_t)bplist->offset_table;
if (!object) if (!object)
return NULL; return NULL;
...@@ -598,6 +600,8 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -598,6 +600,8 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
} }
} }
pobject = (uint64_t)*object;
switch (type) switch (type)
{ {
...@@ -629,14 +633,14 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -629,14 +633,14 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
} }
case BPLIST_UINT: case BPLIST_UINT:
if (*object + (uint64_t)(1 << size) > bplist->offset_table) { if (pobject + (uint64_t)(1 << size) > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_UINT data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_UINT data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
return parse_uint_node(object, size); return parse_uint_node(object, size);
case BPLIST_REAL: case BPLIST_REAL:
if (*object + (uint64_t)(1 << size) > bplist->offset_table) { if (pobject + (uint64_t)(1 << size) > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_REAL data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
...@@ -647,21 +651,21 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -647,21 +651,21 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
PLIST_BIN_ERR("%s: invalid data size for BPLIST_DATE node\n", __func__); PLIST_BIN_ERR("%s: invalid data size for BPLIST_DATE node\n", __func__);
return NULL; return NULL;
} }
if (*object + (uint64_t)(1 << size) > bplist->offset_table) { if (pobject + (uint64_t)(1 << size) > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_DATE data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_DATE data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
return parse_date_node(object, size); return parse_date_node(object, size);
case BPLIST_DATA: case BPLIST_DATA:
if (*object + size < *object || *object + size > bplist->offset_table) { if (pobject + size < pobject || pobject + size > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_DATA data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_DATA data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
return parse_data_node(object, size); return parse_data_node(object, size);
case BPLIST_STRING: case BPLIST_STRING:
if (*object + size < *object || *object + size > bplist->offset_table) { if (pobject + size < pobject || pobject + size > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_STRING data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_STRING data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
...@@ -672,7 +676,7 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -672,7 +676,7 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
PLIST_BIN_ERR("%s: Integer overflow when calculating BPLIST_UNICODE data size.\n", __func__); PLIST_BIN_ERR("%s: Integer overflow when calculating BPLIST_UNICODE data size.\n", __func__);
return NULL; return NULL;
} }
if (*object + size*2 < *object || *object + size*2 > bplist->offset_table) { if (pobject + size*2 < pobject || pobject + size*2 > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_UNICODE data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_UNICODE data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
...@@ -680,21 +684,21 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) ...@@ -680,21 +684,21 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
case BPLIST_SET: case BPLIST_SET:
case BPLIST_ARRAY: case BPLIST_ARRAY:
if (*object + size < *object || *object + size > bplist->offset_table) { if (pobject + size < pobject || pobject + size > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_ARRAY data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_ARRAY data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
return parse_array_node(bplist, object, size); return parse_array_node(bplist, object, size);
case BPLIST_UID: case BPLIST_UID:
if (*object + size+1 > bplist->offset_table) { if (pobject + size+1 > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_UID data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_UID data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
return parse_uid_node(object, size); return parse_uid_node(object, size);
case BPLIST_DICT: case BPLIST_DICT:
if (*object + size < *object || *object + size > bplist->offset_table) { if (pobject + size < pobject || pobject + size > poffset_table) {
PLIST_BIN_ERR("%s: BPLIST_DICT data bytes point outside of valid range\n", __func__); PLIST_BIN_ERR("%s: BPLIST_DICT data bytes point outside of valid range\n", __func__);
return NULL; return NULL;
} }
...@@ -830,7 +834,7 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * ...@@ -830,7 +834,7 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
return; return;
} }
if (offset_table + num_objects * offset_size > end_data) { if ((uint64_t)offset_table + num_objects * offset_size > (uint64_t)end_data) {
PLIST_BIN_ERR("offset table points outside of valid range\n"); PLIST_BIN_ERR("offset table points outside of valid range\n");
return; return;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment