diff options
| author | 2026-11-05 12:01:59 +0100 | |
|---|---|---|
| committer | 2026-11-05 12:01:59 +0100 | |
| commit | 4dc93bc274867b42aa82fc91ee4d5878d23a3f36 (patch) | |
| tree | 11c566b80561bb44018bceea028ea03d47e53458 /src/bplist.c | |
| parent | f252f243f9774b2b830172b49aa340d6994d8081 (diff) | |
| download | libplist-4dc93bc274867b42aa82fc91ee4d5878d23a3f36.tar.gz libplist-4dc93bc274867b42aa82fc91ee4d5878d23a3f36.tar.bz2 | |
Harden allocation failure handling and size arithmetic
- check malloc/calloc/realloc results in constructors, the JSON and
OpenStep writers, the XML text-part helpers and base64 decoding, and
return PLIST_ERR_NO_MEM instead of asserting or dereferencing NULL
- guard size calculations against overflow in the UTF-8/UTF-16BE
conversions, ptrarray, and bytearray
- make hash_table_insert() report failure instead of silently dropping
the entry; writers propagate PLIST_ERR_NO_MEM, and dict lookup caches
are discarded so lookups fall back to a linear search
- don't overwrite an earlier parse error code in the XML parser, and
report PLIST_ERR_NO_MEM when reading text content fails for lack of memory
- OpenStep parser: check node/data/string allocations and dict/array
insertion results
Based on #323 by bg0d-droid.
Co-authored-by: bg0d-droid <81825610+bg0d-droid@users.noreply.github.com>
Diffstat (limited to 'src/bplist.c')
| -rw-r--r-- | src/bplist.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/src/bplist.c b/src/bplist.c index e5ace3a..45caae4 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -397,7 +397,11 @@ static char *plist_utf16be_to_utf8(uint16_t *unistr, size_t len, size_t *items_r uint32_t w; int read_lead_surrogate = 0; - /* allocate with enough space */ + /* allocate with enough space, guarding against integer overflow */ + if (len > (SIZE_MAX / 4) - 1) { + PLIST_BIN_ERR("%s: Input length %" PRIu64 " is too large\n", __func__, (uint64_t)len); + return NULL; + } outbuf = (char*)malloc(4*(len+1)); if (!outbuf) { PLIST_BIN_ERR("%s: Could not allocate %" PRIu64 " bytes\n", __func__, (uint64_t)(4*(len+1))); @@ -1112,13 +1116,18 @@ static plist_err_t serialize_plist(node_t node, void* data, uint32_t depth) } // mark as active - hash_table_insert(ser->in_stack, node, (void*)1); + if (hash_table_insert(ser->in_stack, node, (void*)1) < 0) { + return PLIST_ERR_NO_MEM; + } // insert new ref index_val = (uint64_t *) malloc(sizeof(uint64_t)); if (!index_val) return PLIST_ERR_NO_MEM; *index_val = ser->objects->len; - hash_table_insert(ser->ref_table, node, index_val); + if (hash_table_insert(ser->ref_table, node, index_val) < 0) { + free(index_val); + return PLIST_ERR_NO_MEM; + } // now append current node to object array if (ptr_array_add(ser->objects, node) < 0) { @@ -1228,6 +1237,10 @@ static uint16_t *plist_utf8_to_utf16be(const unsigned char *unistr, size_t size, unsigned char c2; unsigned char c3; + if (size > (SIZE_MAX / sizeof(uint16_t) - 1) / 2) { + PLIST_BIN_ERR("%s: Input size %" PRIu64 " is too large\n", __func__, (uint64_t)size); + return NULL; + } outbuf = (uint16_t*)malloc(((size*2)+1)*sizeof(uint16_t)); if (!outbuf) { PLIST_BIN_ERR("%s: Could not allocate %" PRIu64 " bytes\n", __func__, (uint64_t)((size*2)+1)*sizeof(uint16_t)); |
