diff options
| author | 2026-11-05 10:07:22 +0100 | |
|---|---|---|
| committer | 2026-11-05 10:07:22 +0100 | |
| commit | 2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3 (patch) | |
| tree | 26648136f289451bddef614b124a168cb6b9669a /src/bplist.c | |
| parent | 51f471432715f7a1880d38c135ce41182b4dc78e (diff) | |
| download | libplist-2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3.tar.gz libplist-2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3.tar.bz2 | |
Binary plist objects may be referenced multiple times, and each
reference is parsed into a separate node. A tiny crafted input where
arrays reference the same objects repeatedly (without forming a cycle,
so the recursion check does not trigger) expands into millions of
nodes and exhausts memory.
Track the number of nodes parsed and fail with PLIST_ERR_PARSE once it
exceeds num_objects * 16 + 65536. Legitimate files create roughly as
many nodes as they have objects, so they stay well below this limit.
Credit to OSSFuzz
Diffstat (limited to 'src/bplist.c')
| -rw-r--r-- | src/bplist.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/bplist.c b/src/bplist.c index 8168572..e5ace3a 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -237,6 +237,8 @@ struct bplist_data { uint8_t offset_size; const char* offset_table; uint32_t level; + uint64_t nodes_parsed; + uint64_t max_nodes; ptrarray_t* used_indexes; plist_err_t err; }; @@ -866,6 +868,14 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node return NULL; } + /* Objects can be referenced multiple times, so limit the total number of + nodes created to avoid excessive memory use from reference expansion. */ + if (++bplist->nodes_parsed > bplist->max_nodes) { + PLIST_BIN_ERR("too many nodes created while parsing (reference expansion?)\n"); + bplist->err = PLIST_ERR_PARSE; + return NULL; + } + /* check nesting depth */ if (bplist->level > PLIST_MAX_NESTING_DEPTH) { PLIST_BIN_ERR("maximum nesting depth (%u) exceeded\n",(unsigned)PLIST_MAX_NESTING_DEPTH); @@ -1003,6 +1013,8 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli bplist.offset_size = offset_size; bplist.offset_table = offset_table; bplist.level = 0; + bplist.nodes_parsed = 0; + bplist.max_nodes = num_objects * 16 + 65536; bplist.used_indexes = ptr_array_new(16); bplist.err = PLIST_ERR_SUCCESS; |
